From e15420f2c614447e8287bb77c7ef63c585693ef8 Mon Sep 17 00:00:00 2001 From: Andrew Wilkinson Date: Thu, 13 Aug 2026 10:41:55 +0100 Subject: [PATCH 1/2] feat: add peer cash action provider --- .../.changeset/peer-cash-action-provider.md | 5 + typescript/agentkit/README.md | 37 + typescript/agentkit/package.json | 1 + .../agentkit/src/action-providers/index.ts | 1 + .../src/action-providers/peerCash/README.md | 98 ++ .../src/action-providers/peerCash/index.ts | 7 + .../peerCash/peerCashActionProvider.test.ts | 706 +++++++++++ .../peerCash/peerCashActionProvider.ts | 670 ++++++++++ .../src/action-providers/peerCash/schemas.ts | 135 ++ typescript/pnpm-lock.yaml | 1114 +++-------------- 10 files changed, 1817 insertions(+), 957 deletions(-) create mode 100644 typescript/.changeset/peer-cash-action-provider.md create mode 100644 typescript/agentkit/src/action-providers/peerCash/README.md create mode 100644 typescript/agentkit/src/action-providers/peerCash/index.ts create mode 100644 typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts create mode 100644 typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts create mode 100644 typescript/agentkit/src/action-providers/peerCash/schemas.ts diff --git a/typescript/.changeset/peer-cash-action-provider.md b/typescript/.changeset/peer-cash-action-provider.md new file mode 100644 index 000000000..cabc2d588 --- /dev/null +++ b/typescript/.changeset/peer-cash-action-provider.md @@ -0,0 +1,5 @@ +--- +"@coinbase/agentkit": patch +--- + +Added Peer Cash action provider for cashing out Base USDC to fiat via the Peer P2P protocol diff --git a/typescript/agentkit/README.md b/typescript/agentkit/README.md index 37b14207f..cb99cdb10 100644 --- a/typescript/agentkit/README.md +++ b/typescript/agentkit/README.md @@ -542,6 +542,43 @@ const agent = createAgent({
+Peer Cash + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
estimateEstimates the fiat amount a cash-out would deliver at the live oracle market rate.
capabilitiesLists payout platforms, supported currencies, payee format hints, and USDC amount bounds.
cashoutCashes out USDC to fiat in the user's payment app (Venmo, Revolut, Wise, Zelle, and more) via the Peer P2P protocol.
order_statusReads the lifecycle state of a cash-out order by its deposit id.
list_ordersLists cash-out orders owned by a wallet.
withdrawWithdraws USDC from a cash-out order back to the wallet, pruning expired buyer intents automatically.
top_upAdds USDC to a live cash-out order at the same payee and market rate.
configure_access_policyRetries the access policy transaction for a restricted cash-out whose policy did not confirm.
+
+
Pyth diff --git a/typescript/agentkit/package.json b/typescript/agentkit/package.json index 3bd3fba8b..c3a7216bf 100644 --- a/typescript/agentkit/package.json +++ b/typescript/agentkit/package.json @@ -58,6 +58,7 @@ "@zerodev/ecdsa-validator": "^5.4.5", "@zerodev/intent": "^0.0.24", "@zerodev/sdk": "^5.4.28", + "@zkp2p/cash": "^0.4.8", "@zoralabs/coins-sdk": "0.2.8", "@zoralabs/protocol-deployments": "0.6.1", "agent0-sdk": "^1.7.1", diff --git a/typescript/agentkit/src/action-providers/index.ts b/typescript/agentkit/src/action-providers/index.ts index 9f7164086..c20d91fe6 100644 --- a/typescript/agentkit/src/action-providers/index.ts +++ b/typescript/agentkit/src/action-providers/index.ts @@ -41,3 +41,4 @@ export * from "./zerion"; export * from "./zerodev"; export * from "./zeroX"; export * from "./zora"; +export * from "./peerCash"; diff --git a/typescript/agentkit/src/action-providers/peerCash/README.md b/typescript/agentkit/src/action-providers/peerCash/README.md new file mode 100644 index 000000000..35dfe4661 --- /dev/null +++ b/typescript/agentkit/src/action-providers/peerCash/README.md @@ -0,0 +1,98 @@ +# Peer Cash Action Provider + +This directory contains the **PeerCashActionProvider** implementation, which provides actions to cash out **Base USDC to fiat** in the user's payment app (Venmo, Revolut, Wise, Zelle, and more) via the **Peer P2P protocol**, using the [@zkp2p/cash](https://www.npmjs.com/package/@zkp2p/cash) SDK. + +## Directory Structure + +``` +peerCash/ +├── peerCashActionProvider.ts # Main provider with Peer Cash functionality +├── peerCashActionProvider.test.ts # Test file for Peer Cash provider +├── schemas.ts # Action schemas +├── index.ts # Main exports +└── README.md # This file +``` + +## Actions + +- `estimate`: Estimate the fiat amount a cash-out would deliver + + - Oracle market-rate estimate with zero spread + - Optionally includes the historical median time to first fill + - This is an estimate, not a locked quote; the binding rate resolves when a buyer fills + +- `capabilities`: List payout platforms, currencies, payee format hints, and amount bounds + + - Optionally includes 30-day fill counts and median first-fill times per pair + +- `cashout`: Create a cash-out order + + - Moves USDC from the wallet into the non-custodial Peer escrow contract + - A buyer pays fiat to the payee handle and proves the payment to release the USDC + - Supports a single currency or several currencies the buyer may choose between + - Submits the required access policy transaction automatically for restricted platforms (Venmo, Cash App, PayPal) + - Returns the **depositId**, the resume key for every later action + +- `order_status`: Read the state of an order by deposit id + + - Lifecycle states: awaiting-buyer, matched, delivering, delivered, returned + - Includes a plain-language explanation and the allowed next actions + +- `list_orders`: List orders owned by a wallet + +- `withdraw`: Withdraw USDC from an order back to the wallet + + - The single unwind verb: expired buyer intents are pruned automatically + - Partial with an amount, or full close without + +- `top_up`: Add USDC to a live order + +- `configure_access_policy`: Recovery action for restricted cash-outs + + - Only needed when a cashout reports that the deposit was created but the access policy transaction failed + +## Configuration + +```typescript +import { peerCashActionProvider } from "@coinbase/agentkit"; + +const provider = peerCashActionProvider({ + environment: "production", // "production" (default) | "preproduction" | "staging" + referralCode: "ABC123", // optional, earns the integration share + referrer: "acme-app", // optional, analytics-only attribution + rpcUrl: "https://mainnet.base.org", // optional Base RPC override +}); +``` + +No API keys are required. + +### Earning the integration share + +`referralCode` is the six-character referral code from the Peer mobile or web app. When set, every deposit carries ERC-8021 attribution (`peer-ref-ABC123`) and the code owner earns 50 bps each time an order fills. The mapping is permanent. `referrer` is analytics-only attribution and carries no revenue share. + +## Safety Notes + +- **Non-custodial.** Funds move only between the user's wallet and the Peer escrow contract. Only the escrow holds funds, and only the maker can withdraw an unmatched deposit. +- **The wallet signs locally.** The SDK prepares unsigned transactions; this provider submits them through the AgentKit wallet provider. No keys or approvals leave the host. +- **An estimate is not a locked quote.** Orders fill at the live Chainlink oracle rate with zero spread. The rate binds when a buyer fills, not when the estimate is read. +- **Orders can take time to fill.** The `withdraw` action reclaims unfilled USDC at any time. +- Wise and PayPal payee handles must already be registered with Peer; registering a brand new handle for them requires an identity attestation this provider cannot produce. + +## Network Support + +The Peer Cash provider supports Base mainnet only. The `preproduction` and `staging` environments also settle on Base mainnet, using separate contracts and backend deployments. + +## Adding New Actions + +To add new Peer Cash actions: + +1. Define your action schema in `schemas.ts`. See [Defining the input schema](https://github.com/coinbase/agentkit/blob/main/CONTRIBUTING-TYPESCRIPT.md#defining-the-input-schema) for more information. +2. Implement the action in `peerCashActionProvider.ts` +3. Implement tests in `peerCashActionProvider.test.ts` + +## Notes + +- npm package: [@zkp2p/cash](https://www.npmjs.com/package/@zkp2p/cash) +- Documentation: [docs.peer.xyz/developer/peer-cash](https://docs.peer.xyz/developer/peer-cash) +- Integration prompt: [peer.xyz/cash-sdk](https://peer.xyz/cash-sdk) +- Support: [Peer Builders Club on Telegram](https://t.me/zk_p2p/167174) diff --git a/typescript/agentkit/src/action-providers/peerCash/index.ts b/typescript/agentkit/src/action-providers/peerCash/index.ts new file mode 100644 index 000000000..c778d591b --- /dev/null +++ b/typescript/agentkit/src/action-providers/peerCash/index.ts @@ -0,0 +1,7 @@ +/** + * Exports for peerCash action provider + * + * @module peerCash + */ + +export * from "./peerCashActionProvider"; diff --git a/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts new file mode 100644 index 000000000..86b10906a --- /dev/null +++ b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts @@ -0,0 +1,706 @@ +import { PeerCashActionProvider, peerCashActionProvider } from "./peerCashActionProvider"; +import { CashoutSchema, EstimateSchema, TopUpSchema, WithdrawSchema } from "./schemas"; +import { EvmWalletProvider } from "../../wallet-providers"; +import { createCashClient, CashError } from "@zkp2p/cash"; + +jest.mock("@zkp2p/cash", () => { + interface MockCashErrorShape { + code: string; + message: string; + retryable: boolean; + remediation: string; + recovery?: unknown; + } + + /** + * Runtime stand-in for the SDK's CashError. Tests construct these with real + * error codes; the provider only reads code, message, retryable, + * remediation, and recovery. + */ + class MockCashError extends Error { + code: string; + retryable: boolean; + remediation: string; + recovery?: unknown; + + /** + * Constructor for the MockCashError class. + * + * @param shape - The error shape (code, message, retryable, remediation, recovery). + */ + constructor(shape: MockCashErrorShape) { + super(shape.message); + this.name = "CashError"; + this.code = shape.code; + this.retryable = shape.retryable; + this.remediation = shape.remediation; + if (shape.recovery) this.recovery = shape.recovery; + } + } + + return { + createCashClient: jest.fn(), + CashError: MockCashError, + isCashError: (value: unknown) => value instanceof MockCashError, + usdc: (amount: string | number) => { + const [whole = "0", frac = ""] = String(amount).split("."); + return BigInt(whole) * 1000000n + BigInt((frac + "000000").slice(0, 6)); + }, + capabilitiesToJson: jest.fn(value => value), + cashErrorToJson: jest.fn((error: { code: string; recovery?: unknown }) => ({ + code: error.code, + ...(error.recovery ? { recovery: error.recovery } : {}), + })), + estimateToJson: jest.fn((estimate: { amount: bigint }) => ({ + ...estimate, + amount: estimate.amount.toString(), + })), + fillStatsToJson: jest.fn(value => value), + orderToJson: jest.fn((order: { depositId: string; state: string }) => ({ + depositId: order.depositId, + state: order.state, + })), + }; +}); + +const mockCreateCashClient = createCashClient as jest.MockedFunction; + +const MOCK_ADDRESS = "0x9876543210987654321098765432109876543210"; +const MOCK_DEPOSIT_ID = "0x1111111111111111111111111111111111111111_42"; +const MOCK_TX = { + to: "0x2222222222222222222222222222222222222222" as `0x${string}`, + data: "0xdeadbeef" as `0x${string}`, + value: 0n, + chainId: 8453, +}; +const MOCK_ORDER = { + depositId: MOCK_DEPOSIT_ID, + state: "awaiting-buyer", + fills: [], + totalAmount: 250000000n, + filledAmount: 0n, + pendingAmount: 0n, + returnedAmount: 0n, + nextActions: ["wait", "withdraw"], + isInFlight: true, + explain: () => "Your order is live and waiting for a buyer.", +}; + +/** + * Builds the mocked CashClient surface used across the tests. + * + * @returns An object with every client method the provider calls, as jest mocks. + */ +function buildMockClient() { + return { + capabilities: jest.fn(), + fillStats: jest.fn(), + estimate: jest.fn(), + prepare: jest.fn(), + finalizePreparedCashout: jest.fn(), + prepareAccessPolicy: jest.fn(), + order: jest.fn(), + orders: jest.fn(), + prepareWithdraw: jest.fn(), + prepareTopUp: jest.fn(), + }; +} + +describe("PeerCashActionProvider", () => { + let mockClient: ReturnType; + let mockWallet: jest.Mocked; + let provider: PeerCashActionProvider; + + beforeEach(() => { + jest.clearAllMocks(); + mockClient = buildMockClient(); + mockCreateCashClient.mockReturnValue( + mockClient as unknown as ReturnType, + ); + mockWallet = { + getAddress: jest.fn().mockReturnValue(MOCK_ADDRESS), + getName: jest.fn().mockReturnValue("mock_wallet_provider"), + getNetwork: jest + .fn() + .mockReturnValue({ protocolFamily: "evm", networkId: "base-mainnet", chainId: "8453" }), + sendTransaction: jest.fn().mockResolvedValue("0xhash1" as `0x${string}`), + waitForTransactionReceipt: jest + .fn() + .mockResolvedValue({ status: "success", transactionHash: "0xhash1", logs: [] }), + } as unknown as jest.Mocked; + provider = new PeerCashActionProvider(); + }); + + describe("constructor", () => { + it("defaults to the production environment", () => { + expect(mockCreateCashClient).toHaveBeenCalledWith( + expect.objectContaining({ environment: "production" }), + ); + }); + + it("forwards environment, referralCode, referrer, and rpcUrl", () => { + peerCashActionProvider({ + environment: "staging", + referralCode: "ABC123", + referrer: "acme-app", + rpcUrl: "https://base.example.com", + }); + expect(mockCreateCashClient).toHaveBeenLastCalledWith({ + environment: "staging", + referralCode: "ABC123", + referrer: "acme-app", + rpcUrl: "https://base.example.com", + }); + }); + }); + + describe("supportsNetwork", () => { + it("supports Base mainnet", () => { + expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet" })).toBe( + true, + ); + }); + + it("does not support Base Sepolia", () => { + expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-sepolia" })).toBe( + false, + ); + }); + + it("does not support other EVM networks", () => { + expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum" })).toBe( + false, + ); + }); + + it("does not support non-EVM protocol families", () => { + expect(provider.supportsNetwork({ protocolFamily: "svm", networkId: "base-mainnet" })).toBe( + false, + ); + }); + }); + + describe("estimate", () => { + const ESTIMATE = { + kind: "oracle-estimate", + currency: "EUR", + amount: 250000000n, + rate: 0.92, + receiveAmount: 230, + asOf: 1700000000, + eta: { seconds: 1800, label: "about 30 minutes" }, + }; + + it("returns the oracle estimate with the ETA", async () => { + mockClient.estimate.mockResolvedValue(ESTIMATE); + + const response = await provider.estimate({ amountUsdc: "250", currency: "EUR" }); + + expect(mockClient.estimate).toHaveBeenCalledWith( + { amount: 250000000n, currency: "EUR" }, + { includeEta: true }, + ); + expect(response).toContain("Approximately 230 EUR for 250 USDC"); + expect(response).toContain("not a locked"); + expect(response).toContain("about 30 minutes"); + }); + + it("skips the ETA when includeEta is false", async () => { + const { eta: _, ...withoutEta } = ESTIMATE; + mockClient.estimate.mockResolvedValue(withoutEta); + + const response = await provider.estimate({ + amountUsdc: "250", + currency: "EUR", + includeEta: false, + }); + + expect(mockClient.estimate).toHaveBeenCalledWith( + { amount: 250000000n, currency: "EUR" }, + { includeEta: false }, + ); + expect(response).not.toContain("Estimated time to first fill"); + }); + + it("maps CashErrors to actionable messages", async () => { + mockClient.estimate.mockRejectedValue( + new CashError({ + code: "ORACLE_UNSUPPORTED_CURRENCY", + message: "XYZ has no live Chainlink oracle feed; Peer Cash is market-rate only.", + retryable: false, + remediation: "Pick a currency listed in capabilities().", + }), + ); + + const response = await provider.estimate({ amountUsdc: "250", currency: "XYZ" }); + + expect(response).toContain("Error (ORACLE_UNSUPPORTED_CURRENCY)"); + expect(response).toContain("Remediation: Pick a currency listed in capabilities()."); + expect(response).toContain("Retryable: no"); + }); + }); + + describe("capabilities", () => { + const CAPABILITIES = { + chainId: 8453, + environment: "production", + platforms: [{ platform: "venmo", currencies: ["USD"] }], + currencies: ["USD"], + }; + + it("returns the catalog without fill stats by default", async () => { + mockClient.capabilities.mockReturnValue(CAPABILITIES); + + const response = await provider.capabilities({}); + + expect(response).toContain("environment: production"); + expect(response).toContain("venmo"); + expect(mockClient.fillStats).not.toHaveBeenCalled(); + }); + + it("includes fill stats when requested", async () => { + mockClient.capabilities.mockReturnValue(CAPABILITIES); + mockClient.fillStats.mockResolvedValue({ + "venmo:USD": { fills: 42, medianFillSeconds: 900 }, + }); + + const response = await provider.capabilities({ includeFillStats: true }); + + expect(response).toContain("30-day fill stats"); + expect(response).toContain("venmo:USD"); + }); + + it("fails open to the catalog when fill stats are unavailable", async () => { + mockClient.capabilities.mockReturnValue(CAPABILITIES); + mockClient.fillStats.mockRejectedValue( + new CashError({ + code: "INDEXER_UNAVAILABLE", + message: "The indexer could not be reached.", + retryable: true, + remediation: "Retry the read.", + }), + ); + + const response = await provider.capabilities({ includeFillStats: true }); + + expect(response).toContain("venmo"); + expect(response).toContain("Error (INDEXER_UNAVAILABLE)"); + expect(response).toContain("capabilities above are unaffected"); + }); + }); + + describe("cashout", () => { + const PREPARE_RESULT = { + txs: [MOCK_TX, { ...MOCK_TX, data: "0xfeedface" as `0x${string}` }], + steps: [ + { kind: "approve", description: "Allow the escrow to pull the USDC." }, + { kind: "createDeposit", description: "Create the protocol-held cash-out order." }, + ], + register: { hashedOnchainIds: ["0xabc"] }, + accessPolicyRequired: false, + }; + const CASHOUT_RESULT = { + depositId: MOCK_DEPOSIT_ID, + txHash: "0xhash2", + escrowAddress: "0x3333333333333333333333333333333333333333", + onchainDepositId: 42n, + order: MOCK_ORDER, + }; + + beforeEach(() => { + mockWallet.sendTransaction + .mockResolvedValueOnce("0xhash1" as `0x${string}`) + .mockResolvedValueOnce("0xhash2" as `0x${string}`) + .mockResolvedValueOnce("0xhash3" as `0x${string}`); + mockWallet.waitForTransactionReceipt.mockImplementation(async txHash => ({ + status: "success", + transactionHash: txHash, + logs: [{ address: "0x3333333333333333333333333333333333333333" }], + })); + mockClient.prepare.mockResolvedValue(PREPARE_RESULT); + mockClient.finalizePreparedCashout.mockReturnValue(CASHOUT_RESULT); + }); + + it("submits the prepared transactions in order and finalizes", async () => { + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(mockClient.prepare).toHaveBeenCalledWith({ + amount: 250000000n, + receive: { platform: "venmo", currency: "USD", payee: "@alice" }, + }); + expect(mockWallet.sendTransaction).toHaveBeenNthCalledWith(1, { + to: MOCK_TX.to, + data: MOCK_TX.data, + value: 0n, + }); + expect(mockWallet.sendTransaction).toHaveBeenNthCalledWith(2, { + to: MOCK_TX.to, + data: "0xfeedface", + value: 0n, + }); + expect(mockClient.finalizePreparedCashout).toHaveBeenCalledWith({ + transactionHash: "0xhash2", + status: "success", + logs: [{ address: "0x3333333333333333333333333333333333333333" }], + }); + expect(response).toContain(`Created Peer Cash cash-out order ${MOCK_DEPOSIT_ID}`); + expect(response).toContain("approve: 0xhash1"); + expect(response).toContain("createDeposit: 0xhash2"); + expect(response).toContain("awaiting-buyer"); + }); + + it("passes a multi-currency receive leg through", async () => { + await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "revolut", + currencies: ["EUR", "GBP"], + payee: "revtag", + }); + + expect(mockClient.prepare).toHaveBeenCalledWith({ + amount: 250000000n, + receive: { platform: "revolut", currencies: ["EUR", "GBP"], payee: "revtag" }, + }); + }); + + it("submits the access policy for restricted platforms", async () => { + mockClient.prepare.mockResolvedValue({ ...PREPARE_RESULT, accessPolicyRequired: true }); + mockClient.prepareAccessPolicy.mockReturnValue(MOCK_TX); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(mockClient.prepareAccessPolicy).toHaveBeenCalledWith(MOCK_DEPOSIT_ID); + expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(3); + expect(response).toContain("access policy was configured (transaction: 0xhash3)"); + }); + + it("reports a reverted step without creating an order", async () => { + mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({ + status: "reverted", + transactionHash: "0xhash1", + logs: [], + }); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain("Error: the approve transaction of the cash-out reverted"); + expect(response).toContain("No cash-out order was created"); + expect(mockClient.finalizePreparedCashout).not.toHaveBeenCalled(); + }); + + it("keeps the deposit and points at configure_access_policy when the policy fails", async () => { + mockClient.prepare.mockResolvedValue({ ...PREPARE_RESULT, accessPolicyRequired: true }); + mockClient.prepareAccessPolicy.mockReturnValue(MOCK_TX); + mockWallet.waitForTransactionReceipt + .mockResolvedValueOnce({ status: "success", transactionHash: "0xhash1", logs: [] }) + .mockResolvedValueOnce({ status: "success", transactionHash: "0xhash2", logs: [] }) + .mockResolvedValueOnce({ status: "failed", transactionHash: "0xhash3", logs: [] }); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain(`Created Peer Cash cash-out order ${MOCK_DEPOSIT_ID}`); + expect(response).toContain("access policy transaction reverted"); + expect(response).toContain("never create another cash-out"); + expect(response).toContain("configure_access_policy"); + }); + + it("maps CashErrors from prepare", async () => { + mockClient.prepare.mockRejectedValue( + new CashError({ + code: "AMOUNT_BELOW_MINIMUM", + message: "The amount is below the protocol minimum.", + retryable: false, + remediation: "Cash out at least the minimum from capabilities().", + }), + ); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "0.5", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain("Error (AMOUNT_BELOW_MINIMUM)"); + expect(mockWallet.sendTransaction).not.toHaveBeenCalled(); + }); + }); + + describe("orderStatus", () => { + it("returns the state, explanation, and next actions", async () => { + mockClient.order.mockResolvedValue(MOCK_ORDER); + + const response = await provider.orderStatus({ depositId: MOCK_DEPOSIT_ID }); + + expect(mockClient.order).toHaveBeenCalledWith(MOCK_DEPOSIT_ID); + expect(response).toContain(`Order ${MOCK_DEPOSIT_ID} is awaiting-buyer`); + expect(response).toContain("waiting for a buyer"); + expect(response).toContain("Next actions: wait, withdraw"); + }); + + it("maps ORDER_NOT_FOUND", async () => { + mockClient.order.mockRejectedValue( + new CashError({ + code: "ORDER_NOT_FOUND", + message: "No order exists for that deposit id.", + retryable: false, + remediation: "Check the deposit id.", + }), + ); + + const response = await provider.orderStatus({ depositId: "bogus" }); + + expect(response).toContain("Error (ORDER_NOT_FOUND)"); + }); + }); + + describe("listOrders", () => { + it("defaults to the connected wallet address", async () => { + mockClient.orders.mockResolvedValue([MOCK_ORDER]); + + const response = await provider.listOrders(mockWallet, {}); + + expect(mockClient.orders).toHaveBeenCalledWith(MOCK_ADDRESS, {}); + expect(response).toContain(`Found 1 Peer Cash order(s) for ${MOCK_ADDRESS}`); + expect(response).toContain(MOCK_DEPOSIT_ID); + }); + + it("uses an explicit address and the in-flight filter", async () => { + mockClient.orders.mockResolvedValue([]); + const other = "0x1234567890123456789012345678901234567890"; + + const response = await provider.listOrders(mockWallet, { + address: other, + inFlightOnly: true, + }); + + expect(mockClient.orders).toHaveBeenCalledWith(other, { inFlight: true }); + expect(response).toBe(`No Peer Cash orders found for ${other}.`); + }); + }); + + describe("withdraw", () => { + it("closes the order fully when no amount is given", async () => { + mockClient.prepareWithdraw.mockResolvedValue({ + txs: [MOCK_TX, MOCK_TX], + steps: [ + { kind: "pruneExpiredIntents", description: "Prune expired intents." }, + { kind: "withdrawDeposit", description: "Withdraw the deposit." }, + ], + }); + mockWallet.sendTransaction + .mockResolvedValueOnce("0xhash1" as `0x${string}`) + .mockResolvedValueOnce("0xhash2" as `0x${string}`); + + const response = await provider.withdraw(mockWallet, { depositId: MOCK_DEPOSIT_ID }); + + expect(mockClient.prepareWithdraw).toHaveBeenCalledWith(MOCK_DEPOSIT_ID, {}); + expect(response).toContain(`Closed order ${MOCK_DEPOSIT_ID}`); + expect(response).toContain("pruneExpiredIntents: 0xhash1"); + expect(response).toContain("withdrawDeposit: 0xhash2"); + }); + + it("withdraws a partial amount", async () => { + mockClient.prepareWithdraw.mockResolvedValue({ + txs: [MOCK_TX], + steps: [{ kind: "removeFunds", description: "Withdraw part of the deposit." }], + }); + + const response = await provider.withdraw(mockWallet, { + depositId: MOCK_DEPOSIT_ID, + amountUsdc: "100", + }); + + expect(mockClient.prepareWithdraw).toHaveBeenCalledWith(MOCK_DEPOSIT_ID, { + amount: 100000000n, + }); + expect(response).toContain(`Withdrew 100 USDC from order ${MOCK_DEPOSIT_ID}`); + }); + + it("reports a reverted withdrawal step", async () => { + mockClient.prepareWithdraw.mockResolvedValue({ + txs: [MOCK_TX], + steps: [{ kind: "withdrawDeposit", description: "Withdraw the deposit." }], + }); + mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({ + status: "reverted", + transactionHash: "0xhash1", + logs: [], + }); + + const response = await provider.withdraw(mockWallet, { depositId: MOCK_DEPOSIT_ID }); + + expect(response).toContain("Error: the withdrawDeposit transaction of the withdrawal"); + expect(response).toContain("order_status"); + }); + + it("maps NOTHING_TO_WITHDRAW", async () => { + mockClient.prepareWithdraw.mockRejectedValue( + new CashError({ + code: "NOTHING_TO_WITHDRAW", + message: "The order has no withdrawable funds.", + retryable: false, + remediation: "Check the order state.", + }), + ); + + const response = await provider.withdraw(mockWallet, { depositId: MOCK_DEPOSIT_ID }); + + expect(response).toContain("Error (NOTHING_TO_WITHDRAW)"); + }); + }); + + describe("topUp", () => { + it("submits the prepared top up plan", async () => { + mockClient.prepareTopUp.mockResolvedValue({ + txs: [MOCK_TX, MOCK_TX], + steps: [ + { kind: "approve", description: "Allow the escrow to pull the USDC." }, + { kind: "addFunds", description: "Add funds to the deposit." }, + ], + }); + mockWallet.sendTransaction + .mockResolvedValueOnce("0xhash1" as `0x${string}`) + .mockResolvedValueOnce("0xhash2" as `0x${string}`); + + const response = await provider.topUp(mockWallet, { + depositId: MOCK_DEPOSIT_ID, + amountUsdc: "100", + }); + + expect(mockClient.prepareTopUp).toHaveBeenCalledWith(MOCK_DEPOSIT_ID, 100000000n); + expect(response).toContain(`Added 100 USDC to order ${MOCK_DEPOSIT_ID}`); + expect(response).toContain("addFunds: 0xhash2"); + }); + + it("reports a reverted top up without changing the order", async () => { + mockClient.prepareTopUp.mockResolvedValue({ + txs: [MOCK_TX], + steps: [{ kind: "addFunds", description: "Add funds to the deposit." }], + }); + mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({ + status: "reverted", + transactionHash: "0xhash1", + logs: [], + }); + + const response = await provider.topUp(mockWallet, { + depositId: MOCK_DEPOSIT_ID, + amountUsdc: "100", + }); + + expect(response).toContain("Error: the addFunds transaction of the top up reverted"); + expect(response).toContain("The order is unchanged"); + }); + }); + + describe("configureAccessPolicy", () => { + it("submits and confirms the policy transaction", async () => { + mockClient.prepareAccessPolicy.mockReturnValue(MOCK_TX); + + const response = await provider.configureAccessPolicy(mockWallet, { + depositId: MOCK_DEPOSIT_ID, + }); + + expect(mockClient.prepareAccessPolicy).toHaveBeenCalledWith(MOCK_DEPOSIT_ID); + expect(response).toContain(`Access policy configured for order ${MOCK_DEPOSIT_ID}`); + }); + + it("reports a reverted policy transaction", async () => { + mockClient.prepareAccessPolicy.mockReturnValue(MOCK_TX); + mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({ + status: "reverted", + transactionHash: "0xhash1", + logs: [], + }); + + const response = await provider.configureAccessPolicy(mockWallet, { + depositId: MOCK_DEPOSIT_ID, + }); + + expect(response).toContain("Error: the access policy transaction reverted"); + expect(response).toContain("never create another cash-out"); + }); + + it("maps CashErrors from prepareAccessPolicy", async () => { + mockClient.prepareAccessPolicy.mockImplementation(() => { + throw new CashError({ + code: "ORDER_NOT_FOUND", + message: "No order exists for that deposit id.", + retryable: false, + remediation: "Check the deposit id.", + }); + }); + + const response = await provider.configureAccessPolicy(mockWallet, { + depositId: "bogus", + }); + + expect(response).toContain("Error (ORDER_NOT_FOUND)"); + }); + }); + + describe("schemas", () => { + it("requires exactly one of currency or currencies", () => { + const base = { amountUsdc: "250", platform: "venmo", payee: "@alice" }; + expect(CashoutSchema.safeParse({ ...base, currency: "USD" }).success).toBe(true); + expect(CashoutSchema.safeParse({ ...base, currencies: ["EUR", "GBP"] }).success).toBe(true); + expect(CashoutSchema.safeParse(base).success).toBe(false); + expect( + CashoutSchema.safeParse({ ...base, currency: "USD", currencies: ["EUR"] }).success, + ).toBe(false); + }); + + it("rejects malformed USDC amounts", () => { + expect(EstimateSchema.safeParse({ amountUsdc: "250", currency: "USD" }).success).toBe(true); + expect(EstimateSchema.safeParse({ amountUsdc: "12.34", currency: "USD" }).success).toBe(true); + expect(EstimateSchema.safeParse({ amountUsdc: "-5", currency: "USD" }).success).toBe(false); + expect(EstimateSchema.safeParse({ amountUsdc: "1.1234567", currency: "USD" }).success).toBe( + false, + ); + expect(EstimateSchema.safeParse({ amountUsdc: "usd", currency: "USD" }).success).toBe(false); + }); + + it("rejects lowercase or malformed currency codes", () => { + expect(EstimateSchema.safeParse({ amountUsdc: "250", currency: "usd" }).success).toBe(false); + expect(EstimateSchema.safeParse({ amountUsdc: "250", currency: "USDT" }).success).toBe(false); + }); + + it("allows omitting the withdraw amount but validates it when present", () => { + expect(WithdrawSchema.safeParse({ depositId: MOCK_DEPOSIT_ID }).success).toBe(true); + expect( + WithdrawSchema.safeParse({ depositId: MOCK_DEPOSIT_ID, amountUsdc: "10" }).success, + ).toBe(true); + expect( + WithdrawSchema.safeParse({ depositId: MOCK_DEPOSIT_ID, amountUsdc: "ten" }).success, + ).toBe(false); + }); + + it("requires an amount for top ups", () => { + expect(TopUpSchema.safeParse({ depositId: MOCK_DEPOSIT_ID }).success).toBe(false); + expect(TopUpSchema.safeParse({ depositId: MOCK_DEPOSIT_ID, amountUsdc: "10" }).success).toBe( + true, + ); + }); + }); +}); diff --git a/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts new file mode 100644 index 000000000..5cfbc1caa --- /dev/null +++ b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts @@ -0,0 +1,670 @@ +/** + * Peer Cash Action Provider + * + * This file contains the implementation of the PeerCashActionProvider, which + * provides actions for cashing out Base USDC to fiat in the user's payment app + * (Venmo, Revolut, Wise, Zelle, and more) via the Peer P2P protocol. + * + * @module peerCash + */ + +import { z } from "zod"; +import { + createCashClient, + isCashError, + usdc, + capabilitiesToJson, + cashErrorToJson, + estimateToJson, + fillStatsToJson, + orderToJson, +} from "@zkp2p/cash"; +import type { + CashClient, + CashoutInput, + CashPreparedStep, + CashReceiveLeg, + CurrencyType, + PreparedCashoutReceipt, + PreparedTransaction, +} from "@zkp2p/cash"; +import { ActionProvider } from "../actionProvider"; +import { Network } from "../../network"; +import { CreateAction } from "../actionDecorator"; +import { EvmWalletProvider } from "../../wallet-providers"; +import { + CapabilitiesSchema, + CashoutSchema, + ConfigureAccessPolicySchema, + EstimateSchema, + ListOrdersSchema, + OrderStatusSchema, + TopUpSchema, + WithdrawSchema, +} from "./schemas"; + +/** + * Configuration options for the PeerCashActionProvider. + */ +export interface PeerCashActionProviderConfig { + /** + * Peer protocol environment. Defaults to "production". All environments + * settle on Base mainnet; "preproduction" and "staging" select separate + * escrow contracts and backend deployments for integration testing. + */ + environment?: "production" | "preproduction" | "staging"; + + /** + * Six-character referral code from the Peer mobile or web app. When set, + * deposits carry ERC-8021 attribution and the code owner earns the 50 bps + * integration share each time an order fills. + */ + referralCode?: string; + + /** + * Analytics-only ERC-8021 attribution code(s), e.g. "acme-app". Carries no + * revenue share; use referralCode for the integration share. + */ + referrer?: string | string[]; + + /** + * Base RPC URL override. Defaults to the public Base RPC. + */ + rpcUrl?: string; +} + +/** + * One submitted transaction of a prepared Peer Cash plan. + */ +interface SubmittedStep { + kind: string; + txHash: `0x${string}`; + receipt: TransactionReceiptLike; +} + +/** + * The receipt fields this provider reads. EvmWalletProvider's + * waitForTransactionReceipt is untyped and its shape varies by wallet + * provider (viem transaction receipts vs CDP user operation receipts). + */ +interface TransactionReceiptLike { + status?: unknown; + transactionHash?: `0x${string}`; + logs?: unknown; +} + +/** + * Thrown when a submitted transaction of a prepared plan reverted on-chain. + */ +class StepRevertedError extends Error { + /** + * Constructor for the StepRevertedError class. + * + * @param step - The step kind whose transaction reverted, e.g. "createDeposit". + * @param txHash - The hash of the reverted transaction. + */ + constructor( + readonly step: string, + readonly txHash: `0x${string}`, + ) { + super(`The ${step} transaction reverted (hash: ${txHash})`); + this.name = "StepRevertedError"; + } +} + +/** + * Checks whether a wallet provider receipt reports an on-chain failure. + * Viem receipts report "success" or "reverted"; CDP user operation receipts + * report "complete" or "failed". + * + * @param receipt - The receipt returned by waitForTransactionReceipt. + * @returns True when the receipt carries an explicit failure marker. + */ +function isRevertedReceipt(receipt: TransactionReceiptLike | null | undefined): boolean { + const status = receipt?.status; + return status === "reverted" || status === "failed" || status === 0 || status === "0x0"; +} + +/** + * Formats an error from a Peer Cash operation into an actionable message. + * CashErrors carry a stable code, whether the operation is retryable, a + * remediation sentence, and optional recovery data; all of it is surfaced so + * the agent can self-drive recovery instead of guessing. + * + * @param operation - Short description of the operation that failed. + * @param error - The thrown error. + * @returns A human-readable error message. + */ +function describeCashError(operation: string, error: unknown): string { + if (isCashError(error)) { + const parts = [ + `Error (${error.code}) while ${operation}: ${error.message}`, + `Remediation: ${error.remediation}`, + `Retryable: ${error.retryable ? "yes" : "no"}.`, + ]; + if (error.recovery) { + parts.push(`Recovery data: ${JSON.stringify(cashErrorToJson(error).recovery)}`); + } + return parts.join(" "); + } + return `Error while ${operation}: ${error}`; +} + +/** + * PeerCashActionProvider provides actions for cashing out Base USDC to fiat + * via the Peer P2P protocol (peer.xyz). + * + * @description + * The wallet is the maker: its USDC moves into the non-custodial Peer escrow + * contract, a buyer pays fiat to the configured payment handle and proves the + * payment, and the escrow releases the USDC. Orders fill at the live Chainlink + * oracle market rate with zero spread; there are no locked quotes and no API + * keys. Every order is resumable from its deposit id alone, and unfilled USDC + * can be withdrawn at any time. + */ +export class PeerCashActionProvider extends ActionProvider { + readonly #client: CashClient; + + /** + * Constructor for the PeerCashActionProvider class. + * + * @param config - Configuration options, including the Peer environment and + * an optional referral code for the integration share. + */ + constructor(config: PeerCashActionProviderConfig = {}) { + super("peerCash", []); + // createCashClient validates the referral code eagerly, so a bad code + // fails at construction instead of on the first cash-out. + this.#client = createCashClient({ + environment: config.environment ?? "production", + referralCode: config.referralCode, + referrer: config.referrer, + rpcUrl: config.rpcUrl, + }); + } + + /** + * Estimates the fiat amount a cash-out would deliver for a USDC amount. + * + * @param args - The input arguments for the action. + * @returns A message containing the oracle estimate. + */ + @CreateAction({ + name: "estimate", + description: ` +This tool estimates the fiat amount a Peer Cash cash-out would deliver for a given USDC amount. + +It takes: +- amountUsdc: The USDC amount to cash out, in whole units (e.g. '250' or '12.34') +- currency: The target fiat currency code (e.g. 'USD') +- includeEta: (Optional) Whether to include the historical time-to-fill estimate (default true) + +Important notes: +- The result is an oracle market-rate estimate, not a locked quote. The binding rate resolves at the Chainlink oracle when a buyer fills the order, always with zero spread. +- The ETA is historical evidence (median time to first fill over the last 30 days), not a guarantee. +- Use the capabilities action to discover supported platforms and currencies. +`, + schema: EstimateSchema, + }) + async estimate(args: z.infer): Promise { + try { + const estimate = await this.#client.estimate( + // Currency support is validated by the SDK, which throws a typed + // ORACLE_UNSUPPORTED_CURRENCY error for anything without a live feed. + { amount: usdc(args.amountUsdc), currency: args.currency as CurrencyType }, + { includeEta: args.includeEta ?? true }, + ); + const eta = estimate.eta ? ` Estimated time to first fill: ${estimate.eta.label}.` : ""; + // Round the headline number for readability; the JSON below keeps full precision. + const receive = Number(estimate.receiveAmount.toFixed(2)); + return ( + `Approximately ${receive} ${estimate.currency} for ${args.amountUsdc} USDC ` + + `at the current oracle rate of ${estimate.rate} (zero spread). This is not a locked ` + + `quote; the binding rate resolves when a buyer fills.${eta}\n` + + JSON.stringify(estimateToJson(estimate), null, 2) + ); + } catch (error) { + return describeCashError("estimating the cash-out", error); + } + } + + /** + * Lists the payout platforms, currencies, payee format hints, and amount + * bounds Peer Cash supports, optionally with 30-day fill statistics. + * + * @param args - The input arguments for the action. + * @returns A message containing the capability catalog. + */ + @CreateAction({ + name: "capabilities", + description: ` +This tool lists what Peer Cash can pay out: payout platforms, the fiat currencies each platform supports, payee handle format hints, and USDC amount bounds. + +It takes: +- includeFillStats: (Optional) Also include 30-day fill counts and median first-fill times per platform and currency pair (default false) + +Important notes: +- Call this before the first cashout to pick a platform and currency and to learn the payee handle format from each platform's payeeHint. +- Platforms with requiresIdentityAttestation true (currently Wise and PayPal) only accept payee handles already registered with Peer; this provider cannot register a brand new handle for them. +- Fill stats are raw evidence. A reasonable availability gate is fills >= 10 and medianFillSeconds <= 48 hours; fail open to the full catalog when stats are unavailable. +`, + schema: CapabilitiesSchema, + }) + async capabilities(args: z.infer): Promise { + const capabilities = this.#client.capabilities(); + const catalog = + `Peer Cash payout capabilities (environment: ${capabilities.environment}):\n` + + JSON.stringify(capabilitiesToJson(capabilities), null, 2); + if (!args.includeFillStats) { + return catalog; + } + try { + const stats = await this.#client.fillStats(); + return `${catalog}\n30-day fill stats by pair:\n${JSON.stringify(fillStatsToJson(stats), null, 2)}`; + } catch (error) { + // Fill stats are an optional signal; fail open to the full catalog. + return `${catalog}\n${describeCashError("reading fill stats (capabilities above are unaffected)", error)}`; + } + } + + /** + * Creates a cash-out order: moves USDC from the wallet into the Peer escrow + * contract, where a buyer pays fiat to the payee handle to earn it. + * + * @param walletProvider - The wallet provider that funds and signs the order. + * @param args - The input arguments for the action. + * @returns A message containing the deposit id and transaction details. + */ + @CreateAction({ + name: "cashout", + description: ` +This tool cashes out USDC from the wallet to fiat in the user's payment app via the Peer P2P protocol. + +It takes: +- amountUsdc: The USDC amount to cash out, in whole units (e.g. '250') +- platform: The payout platform id from the capabilities action (e.g. 'venmo') +- currency: The fiat currency to receive (e.g. 'USD'), or +- currencies: Several fiat currencies the buyer may choose between (e.g. ['EUR', 'GBP']); provide exactly one of currency or currencies +- payee: The payment handle that receives the fiat, formatted per the platform's payeeHint from the capabilities action + +Important notes: +- This moves funds. The USDC leaves the wallet into the non-custodial Peer escrow contract; a buyer then pays fiat to the payee handle and proves the payment to release the USDC. +- The order fills at the live oracle market rate with zero spread. There is no locked quote. +- The returned depositId is the resume key. Persist it: the order_status, withdraw, and top_up actions all take it. +- Filling can take time. Poll with the order_status action; the withdraw action reclaims unfilled USDC at any time. +- If the platform is venmo, cashapp, or paypal, a follow-up access policy transaction is submitted automatically after the deposit confirms. +- If this tool reports that the deposit was created but the access policy failed, use the configure_access_policy action. Never create a second cash-out for the same funds. +`, + schema: CashoutSchema, + }) + async cashout( + walletProvider: EvmWalletProvider, + args: z.infer, + ): Promise { + try { + const receive = ( + args.currencies !== undefined + ? { platform: args.platform, currencies: args.currencies, payee: args.payee } + : { platform: args.platform, currency: args.currency, payee: args.payee } + ) as CashReceiveLeg; + const input: CashoutInput = { amount: usdc(args.amountUsdc), receive }; + const prepared = await this.#client.prepare(input); + + let submitted: SubmittedStep[]; + try { + submitted = await this.#submitPreparedPlan(walletProvider, prepared.txs, prepared.steps); + } catch (error) { + if (error instanceof StepRevertedError) { + return ( + `Error: the ${error.step} transaction of the cash-out reverted ` + + `(hash: ${error.txHash}). No cash-out order was created and no USDC is in escrow.` + ); + } + throw error; + } + + const depositStep = submitted.find(step => step.kind === "createDeposit"); + if (!depositStep) { + return "Error: the prepared cash-out plan had no createDeposit step; no order was created."; + } + const result = this.#client.finalizePreparedCashout({ + // Smart wallet providers return user operation receipts; their + // transactionHash is the containing transaction that holds the logs. + transactionHash: depositStep.receipt.transactionHash ?? depositStep.txHash, + status: "success", + logs: (depositStep.receipt.logs ?? []) as PreparedCashoutReceipt["logs"], + }); + + let accessPolicyNote = ""; + if (prepared.accessPolicyRequired) { + try { + const policyTxHash = await this.#submitAccessPolicy(walletProvider, result.depositId); + accessPolicyNote = ` The restricted-platform access policy was configured (transaction: ${policyTxHash}).`; + } catch (error) { + const reason = + error instanceof StepRevertedError + ? `the access policy transaction reverted (hash: ${error.txHash})` + : describeCashError("configuring the access policy", error); + return ( + `Created Peer Cash cash-out order ${result.depositId} for ${args.amountUsdc} USDC on ` + + `${args.platform} (deposit transaction: ${result.txHash}), but ${reason}. The USDC is ` + + `already in escrow under this order, so never create another cash-out for the same ` + + `funds. Retry the policy with the configure_access_policy action for deposit ` + + `${result.depositId}, or use the withdraw action to unwind.` + ); + } + } + + const steps = submitted.map(step => `${step.kind}: ${step.txHash}`).join(", "); + return ( + `Created Peer Cash cash-out order ${result.depositId} for ${args.amountUsdc} USDC on ` + + `${args.platform} (transactions: ${steps}).${accessPolicyNote} The order is now ` + + `${result.order.state}: a buyer pays fiat to '${args.payee}' at the live oracle rate ` + + `and the escrow releases the USDC once the payment is proven. Track it with the ` + + `order_status action; the withdraw action reclaims unfilled USDC at any time.` + ); + } catch (error) { + return describeCashError("creating the cash-out", error); + } + } + + /** + * Reads the current state of a cash-out order by its deposit id. + * + * @param args - The input arguments for the action. + * @returns A message containing the order state and details. + */ + @CreateAction({ + name: "order_status", + description: ` +This tool reads the current state of a Peer Cash cash-out order by its deposit id. + +It takes: +- depositId: The deposit id returned by the cashout action + +The result includes the lifecycle state (awaiting-buyer, matched, delivering, delivered, or returned), a plain-language explanation, the allowed next actions (wait or withdraw), and per-fill receipts (locked rate, fiat owed, verified fiat paid, released USDC). Orders are resumable: any depositId can be inspected at any time, from any process. +`, + schema: OrderStatusSchema, + }) + async orderStatus(args: z.infer): Promise { + try { + const order = await this.#client.order(args.depositId); + return ( + `Order ${args.depositId} is ${order.state}. ${order.explain()} ` + + `Next actions: ${order.nextActions.join(", ") || "none"}.\n` + + JSON.stringify(orderToJson(order), null, 2) + ); + } catch (error) { + return describeCashError("reading the order status", error); + } + } + + /** + * Lists cash-out orders owned by a wallet address. + * + * @param walletProvider - The wallet provider supplying the default address. + * @param args - The input arguments for the action. + * @returns A message containing the list of orders. + */ + @CreateAction({ + name: "list_orders", + description: ` +This tool lists Peer Cash cash-out orders owned by a wallet. + +It takes: +- address: (Optional) The wallet address to list orders for (defaults to the connected wallet) +- inFlightOnly: (Optional) Only return orders that still need attention: awaiting a buyer, matched, or delivering (default false) +`, + schema: ListOrdersSchema, + }) + async listOrders( + walletProvider: EvmWalletProvider, + args: z.infer, + ): Promise { + const owner = args.address ?? walletProvider.getAddress(); + try { + const orders = await this.#client.orders(owner, args.inFlightOnly ? { inFlight: true } : {}); + if (orders.length === 0) { + return `No Peer Cash orders found for ${owner}.`; + } + return ( + `Found ${orders.length} Peer Cash order(s) for ${owner}:\n` + + JSON.stringify(orders.map(orderToJson), null, 2) + ); + } catch (error) { + return describeCashError("listing orders", error); + } + } + + /** + * Withdraws USDC from a cash-out order back to the wallet. + * + * @param walletProvider - The wallet provider that signs the withdrawal. + * @param args - The input arguments for the action. + * @returns A message containing the withdrawal transaction details. + */ + @CreateAction({ + name: "withdraw", + description: ` +This tool withdraws USDC from a Peer Cash cash-out order back to the wallet. + +It takes: +- depositId: The deposit id of the order +- amountUsdc: (Optional) A partial USDC amount to withdraw; omit to close the order fully + +Important notes: +- This is the single unwind verb. If a buyer never paid, their expired intent is pruned automatically and the USDC comes back; there is no separate cancel. +- A partial withdrawal takes only unlocked funds; a live buyer intent does not block it. +- Omitting amountUsdc closes the order and returns everything not already taken by proven fills. +`, + schema: WithdrawSchema, + }) + async withdraw( + walletProvider: EvmWalletProvider, + args: z.infer, + ): Promise { + try { + const prepared = await this.#client.prepareWithdraw( + args.depositId, + args.amountUsdc !== undefined ? { amount: usdc(args.amountUsdc) } : {}, + ); + const submitted = await this.#submitPreparedPlan( + walletProvider, + prepared.txs, + prepared.steps, + ); + const steps = submitted.map(step => `${step.kind}: ${step.txHash}`).join(", "); + const summary = + args.amountUsdc !== undefined + ? `Withdrew ${args.amountUsdc} USDC from order ${args.depositId}` + : `Closed order ${args.depositId} and withdrew the remaining USDC`; + return `${summary} (transactions: ${steps}).`; + } catch (error) { + if (error instanceof StepRevertedError) { + return ( + `Error: the ${error.step} transaction of the withdrawal reverted ` + + `(hash: ${error.txHash}). Check the order with the order_status action before retrying.` + ); + } + return describeCashError("withdrawing from the order", error); + } + } + + /** + * Adds USDC to a live cash-out order. + * + * @param walletProvider - The wallet provider that funds and signs the top up. + * @param args - The input arguments for the action. + * @returns A message containing the top up transaction details. + */ + @CreateAction({ + name: "top_up", + description: ` +This tool adds USDC to a live Peer Cash cash-out order. + +It takes: +- depositId: The deposit id of the order +- amountUsdc: The USDC amount to add, in whole units (e.g. '100') + +The added funds pay out to the same payee and fill at the same live oracle market rate. This moves funds from the wallet into the escrow contract. +`, + schema: TopUpSchema, + }) + async topUp( + walletProvider: EvmWalletProvider, + args: z.infer, + ): Promise { + try { + const prepared = await this.#client.prepareTopUp(args.depositId, usdc(args.amountUsdc)); + const submitted = await this.#submitPreparedPlan( + walletProvider, + prepared.txs, + prepared.steps, + ); + const steps = submitted.map(step => `${step.kind}: ${step.txHash}`).join(", "); + return `Added ${args.amountUsdc} USDC to order ${args.depositId} (transactions: ${steps}).`; + } catch (error) { + if (error instanceof StepRevertedError) { + return ( + `Error: the ${error.step} transaction of the top up reverted (hash: ${error.txHash}). ` + + `The order is unchanged.` + ); + } + return describeCashError("topping up the order", error); + } + } + + /** + * Retries the access policy transaction for a restricted cash-out whose + * deposit exists but whose policy did not confirm. + * + * @param walletProvider - The wallet provider that signs the policy transaction. + * @param args - The input arguments for the action. + * @returns A message containing the policy transaction details. + */ + @CreateAction({ + name: "configure_access_policy", + description: ` +This tool retries the access policy transaction for a restricted Peer Cash cash-out (venmo, cashapp, or paypal). + +It takes: +- depositId: The deposit id of the order that still needs its access policy + +Important notes: +- Only use this when a cashout reported that the deposit was created but the access policy transaction failed. The cashout action submits the policy automatically in the normal case. +- Never create a second cash-out to fix a policy failure; the USDC is already in escrow under the existing deposit id. +`, + schema: ConfigureAccessPolicySchema, + }) + async configureAccessPolicy( + walletProvider: EvmWalletProvider, + args: z.infer, + ): Promise { + try { + const txHash = await this.#submitAccessPolicy(walletProvider, args.depositId); + return ( + `Access policy configured for order ${args.depositId} (transaction: ${txHash}). ` + + `Intent signaling is now restricted to the required buyer groups.` + ); + } catch (error) { + if (error instanceof StepRevertedError) { + return ( + `Error: the access policy transaction reverted (hash: ${error.txHash}). Inspect that ` + + `transaction before retrying, and never create another cash-out for the same funds.` + ); + } + return describeCashError("configuring the access policy", error); + } + } + + /** + * Checks if the Peer Cash action provider supports the given network. + * Peer Cash settles exclusively on Base mainnet; the preproduction and + * staging environments also run on Base mainnet with separate contracts. + * + * @param network - The network to check. + * @returns True if the network is Base mainnet. + */ + supportsNetwork(network: Network): boolean { + return network.protocolFamily === "evm" && network.networkId === "base-mainnet"; + } + + /** + * Submits the transactions of a prepared Peer Cash plan in order, waiting + * for each receipt before continuing. + * + * Peer Cash's signed path wants a viem WalletClient, which an AgentKit + * EvmWalletProvider is not guaranteed to expose (CDP server and smart + * wallets sign remotely and cannot produce raw signed transactions). The + * SDK's unsigned prepare path returns the exact transactions with a + * same-index step plan, so this provider submits them through + * walletProvider.sendTransaction and every AgentKit wallet provider works + * unchanged. + * + * @param walletProvider - The wallet provider that signs and submits. + * @param txs - The unsigned transactions, in submission order. + * @param steps - The step labels, same order as the transactions. + * @returns The submitted steps with their transaction hashes and receipts. + */ + async #submitPreparedPlan( + walletProvider: EvmWalletProvider, + txs: PreparedTransaction[], + steps: CashPreparedStep[], + ): Promise { + const submitted: SubmittedStep[] = []; + for (let i = 0; i < txs.length; i++) { + const tx = txs[i]; + const kind = steps[i]?.kind ?? "transaction"; + const txHash = await walletProvider.sendTransaction({ + to: tx.to, + data: tx.data, + value: tx.value, + }); + const receipt = (await walletProvider.waitForTransactionReceipt( + txHash, + )) as TransactionReceiptLike; + if (isRevertedReceipt(receipt)) { + throw new StepRevertedError(kind, txHash); + } + submitted.push({ kind, txHash, receipt }); + } + return submitted; + } + + /** + * Prepares, submits, and confirms the restricted-platform access policy + * transaction for a deposit. + * + * @param walletProvider - The wallet provider that signs the policy transaction. + * @param depositId - The deposit id to attach the policy to. + * @returns The confirmed policy transaction hash. + */ + async #submitAccessPolicy( + walletProvider: EvmWalletProvider, + depositId: string, + ): Promise<`0x${string}`> { + const policyTx = this.#client.prepareAccessPolicy(depositId); + const txHash = await walletProvider.sendTransaction({ + to: policyTx.to, + data: policyTx.data, + value: policyTx.value, + }); + const receipt = (await walletProvider.waitForTransactionReceipt( + txHash, + )) as TransactionReceiptLike; + if (isRevertedReceipt(receipt)) { + throw new StepRevertedError("accessPolicy", txHash); + } + return txHash; + } +} + +/** + * Factory function to create a new PeerCashActionProvider instance. + * + * @param config - Configuration options, including the Peer environment and + * an optional referral code for the integration share. + * @returns A new PeerCashActionProvider instance. + */ +export const peerCashActionProvider = (config: PeerCashActionProviderConfig = {}) => + new PeerCashActionProvider(config); diff --git a/typescript/agentkit/src/action-providers/peerCash/schemas.ts b/typescript/agentkit/src/action-providers/peerCash/schemas.ts new file mode 100644 index 000000000..36865c95d --- /dev/null +++ b/typescript/agentkit/src/action-providers/peerCash/schemas.ts @@ -0,0 +1,135 @@ +import { z } from "zod"; + +/** + * Action schemas for the peerCash action provider. + * + * Peer Cash amounts are expressed as decimal USDC strings ("250" or "12.34", + * at most 6 decimal places). The provider converts them to USDC base units. + */ + +const usdcAmount = z + .string() + .regex(/^\d+(\.\d{1,6})?$/, "Must be a decimal USDC amount with at most 6 decimal places") + .describe("The USDC amount in whole units, e.g. '250' or '12.34'"); + +const currencyCode = z + .string() + .regex(/^[A-Z]{3}$/, "Must be a three-letter uppercase ISO 4217 currency code") + .describe("Three-letter fiat currency code, e.g. 'USD' or 'EUR'"); + +const depositId = z + .string() + .min(1) + .describe("The deposit id of the cash-out order, as returned by the cashout action"); + +/** + * Input schema for the estimate action. + */ +export const EstimateSchema = z + .object({ + amountUsdc: usdcAmount, + currency: currencyCode, + includeEta: z + .boolean() + .optional() + .describe("Include the historical fill-time estimate (default true)"), + }) + .describe("Input schema for estimating a Peer Cash fiat payout"); + +/** + * Input schema for the capabilities action. + */ +export const CapabilitiesSchema = z + .object({ + includeFillStats: z + .boolean() + .optional() + .describe("Include 30-day fill counts and median first-fill times per pair (default false)"), + }) + .describe("Input schema for listing Peer Cash payout capabilities"); + +/** + * Input schema for the cashout action. Exactly one of `currency` or + * `currencies` must be provided. + */ +export const CashoutSchema = z + .object({ + amountUsdc: usdcAmount, + platform: z + .string() + .min(1) + .describe("Payout platform id from the capabilities action, e.g. 'venmo' or 'revolut'"), + currency: currencyCode.optional().describe("The single fiat currency to receive, e.g. 'USD'"), + currencies: z + .array(currencyCode) + .min(1) + .optional() + .describe("Multiple fiat currencies the buyer may pay in, e.g. ['EUR', 'GBP', 'USD']"), + payee: z + .string() + .min(1) + .describe( + "The payment handle that receives the fiat, formatted per the platform's payeeHint", + ), + }) + .refine(args => (args.currency === undefined) !== (args.currencies === undefined), { + message: "Provide exactly one of currency or currencies", + }) + .describe("Input schema for creating a Peer Cash cash-out order"); + +/** + * Input schema for the order status action. + */ +export const OrderStatusSchema = z + .object({ + depositId, + }) + .describe("Input schema for reading the state of a Peer Cash order"); + +/** + * Input schema for the list orders action. + */ +export const ListOrdersSchema = z + .object({ + address: z + .string() + .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format") + .optional() + .describe("Wallet address to list orders for (defaults to the connected wallet)"), + inFlightOnly: z + .boolean() + .optional() + .describe("Only return orders that still need attention (default false)"), + }) + .describe("Input schema for listing Peer Cash orders for a wallet"); + +/** + * Input schema for the withdraw action. + */ +export const WithdrawSchema = z + .object({ + depositId, + amountUsdc: usdcAmount + .optional() + .describe("Partial USDC amount to withdraw; omit to close the order fully"), + }) + .describe("Input schema for withdrawing USDC from a Peer Cash order"); + +/** + * Input schema for the top up action. + */ +export const TopUpSchema = z + .object({ + depositId, + amountUsdc: usdcAmount, + }) + .describe("Input schema for adding USDC to a live Peer Cash order"); + +/** + * Input schema for the configure access policy recovery action. + */ +export const ConfigureAccessPolicySchema = z + .object({ + depositId, + }) + .describe("Input schema for attaching the required access policy to a restricted cash-out"); diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index dc1ba0ed4..435c4f08d 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -109,7 +109,7 @@ importers: version: 2.7.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) '@x402/svm': specifier: ^2.7.0 - version: 2.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + version: 2.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@zerodev/ecdsa-validator': specifier: ^5.4.5 version: 5.4.5(@zerodev/sdk@5.4.28(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) @@ -119,6 +119,9 @@ importers: '@zerodev/sdk': specifier: ^5.4.28 version: 5.4.28(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) + '@zkp2p/cash': + specifier: ^0.4.8 + version: 0.4.8(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) '@zoralabs/coins-sdk': specifier: 0.2.8 version: 0.2.8(abitype@1.0.8(typescript@5.8.2)(zod@4.3.6))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) @@ -136,7 +139,7 @@ importers: version: 2.1.0 clanker-sdk: specifier: ^4.1.18 - version: 4.1.19(@types/node@22.13.14)(typescript@5.8.2)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) + version: 4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) decimal.js: specifier: ^10.5.0 version: 10.5.0 @@ -191,7 +194,7 @@ importers: version: 14.1.1 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) + version: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)) mock-fs: specifier: ^5.2.0 version: 5.5.0 @@ -209,7 +212,7 @@ importers: version: 2.4.2 ts-jest: specifier: ^29.2.5 - version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)))(typescript@5.8.2) tsd: specifier: ^0.31.2 version: 0.31.2 @@ -698,22 +701,6 @@ importers: specifier: ^4.7.1 version: 4.19.3 - examples/register: - dependencies: - '@coinbase/agentkit': - specifier: latest - version: 0.10.4(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(@types/node@20.17.27)(abitype@1.2.3(typescript@5.8.2)(zod@3.25.56))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(graphql@16.11.0)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - dotenv: - specifier: ^16.4.5 - version: 16.4.7 - viem: - specifier: ^2.21.19 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - devDependencies: - tsx: - specifier: ^4.7.1 - version: 4.19.3 - examples/vercel-ai-sdk-smart-wallet-chatbot: dependencies: '@ai-sdk/openai': @@ -1130,24 +1117,15 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@coinbase/agentkit@0.10.4': - resolution: {integrity: sha512-1ZnjY6ohuBXqseZDUhrkFnlU+UjNBr9TeZjpa4wjR8pGQq2RhhVKXQSe5UOFpitgtK3z8ytsQXTHwKRohkExKw==} - '@coinbase/cdp-sdk@1.45.0': resolution: {integrity: sha512-4fgGOhyN9g/pTDE9NtsKUapwFsubrk9wafz8ltmBqSwWqLZWfWxXkVmzMYYFAf+qeGf/X9JqJtmvDVaHFlXWlw==} - '@coinbase/coinbase-sdk@0.20.0': - resolution: {integrity: sha512-OoMMktKbjmeEwtwQCK3kIIoX5M+hNelxAGX5Llymvw6bmyrMDaEBZ/Myga9kaLJ+7Hi5Y4jPDy4Cy2MGxxXg6w==} - '@coinbase/wallet-sdk@3.9.3': resolution: {integrity: sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==} '@coinbase/wallet-sdk@4.3.6': resolution: {integrity: sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==} - '@coinbase/x402@0.6.4': - resolution: {integrity: sha512-T0tNU8/oZ64GaKC3dbGcOFHqYO0BjII/uZeC/tAS9HOqhWBvewhoa0rzPzaE8SHeKOIwX2YpbFXdG0Hyh0d4mw==} - '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -1911,6 +1889,7 @@ packages: '@metamask/sdk-communication-layer@0.32.0': resolution: {integrity: sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect peerDependencies: cross-fetch: ^4.0.0 eciesjs: '*' @@ -1920,9 +1899,11 @@ packages: '@metamask/sdk-install-modal-web@0.32.0': resolution: {integrity: sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect '@metamask/sdk@0.32.0': resolution: {integrity: sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect '@metamask/superstruct@3.2.1': resolution: {integrity: sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==} @@ -2086,7 +2067,7 @@ packages: '@paulmillr/qr@0.2.1': resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} - deprecated: 'The package is now available as "qr": npm install qr' + deprecated: 'Switch to "qr" (new package name) for security updates: npm install qr' '@peculiar/asn1-cms@2.6.1': resolution: {integrity: sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==} @@ -2241,6 +2222,11 @@ packages: '@types/react': optional: true + '@relayprotocol/relay-sdk@6.1.3': + resolution: {integrity: sha512-JD6Cn6ejynKCiZo0NrMDC0bU7IJfJNWqCLr9NHCpV2s48T01zy+8uN+joBFVawsiRxakApgPkdE8FlQAeQxduA==} + peerDependencies: + viem: '>=2.26.0' + '@reown/appkit-common@1.7.8': resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} @@ -2282,6 +2268,7 @@ packages: '@safe-global/safe-gateway-typescript-sdk@3.23.1': resolution: {integrity: sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==} engines: {node: '>=16'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@scure/base@1.1.9': resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} @@ -3287,6 +3274,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@uniswap/token-lists@1.0.0-beta.33': resolution: {integrity: sha512-JQkXcpRI3jFG8y3/CGC4TS8NkDgcxXaOQuYW8Qdvd6DcDiIyg2vVYCG9igFEzF0G6UvxgHkBKC7cWCgzZNYvQg==} @@ -3507,6 +3495,40 @@ packages: peerDependencies: viem: ^2.23.15 + '@zkp2p/cash@0.4.8': + resolution: {integrity: sha512-+JwFs2RFjzw9L0szLXuILJukE8acQXXE1WZlRJXxEQx9aFauJ/Rq8dqdx1AIs3xTZ8tG9eHRXkM1Dvx6daDaEg==} + engines: {node: '>=22'} + peerDependencies: + react: '>=18' + viem: '>=2.37.3 <3' + peerDependenciesMeta: + react: + optional: true + + '@zkp2p/contracts-v2@0.4.0': + resolution: {integrity: sha512-wE4IfjRSUVfOiAULoh6eVUj5vExSlcMY6+VsRLOhGq+1q06uy/aS2lMYjzqoDAXibMpYPTVhsuy1MEB2jKGKqw==} + peerDependencies: + ethers: ^5.0.0 || ^6.0.0 + + '@zkp2p/indexer-schema@0.20.0': + resolution: {integrity: sha512-EQsmFfp61hI0zzILYoh8aPzf+CGeduoiAQQ+FD27oIQBj5piKFqNQCfzhI14A7lBWtS69gXqjPuJJTo/BOaO3w==} + engines: {node: '>=16'} + + '@zkp2p/sdk@0.12.0': + resolution: {integrity: sha512-7boAYdUV+R3G+1hFOp7lQLxX9NUDVXtfW3RsgBt4ijhg3BqO9RBgpMfeWfqoE7kRUVDo/xNZL39bhBbXK6NmIA==} + engines: {node: '>=22'} + peerDependencies: + react: '>=16.8.0' + viem: ^2.37.3 + peerDependenciesMeta: + react: + optional: true + + '@zkp2p/zkp2p-attestation@2.0.0': + resolution: {integrity: sha512-m+HWDYTEW109xSqh0NWJFoWR0ZIoxJqQRguQltfr6RSkALBJFWv5WWDQrcPN0TiqTN2KdLI7BYQTDluZfjq2MA==} + engines: {node: '>=20'} + hasBin: true + '@zoralabs/coins-sdk@0.2.8': resolution: {integrity: sha512-vni9qcdS6/9HUOue7SDir2wHn+SSSDmxfZhBcCzQWdK9NaW/+E5jCWXuQGFgBzKpLc4FN5ktJz36v92BADQE3g==} engines: {node: '>=22'} @@ -3769,11 +3791,6 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axios-mock-adapter@1.22.0: - resolution: {integrity: sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==} - peerDependencies: - axios: '>= 0.17.0' - axios-retry@4.5.0: resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} peerDependencies: @@ -3859,13 +3876,6 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bip32@4.0.0: - resolution: {integrity: sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==} - engines: {node: '>=6.0.0'} - - bip39@3.1.0: - resolution: {integrity: sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==} - bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -3934,9 +3944,6 @@ packages: bs58@6.0.0: resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} - bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} - bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -4069,10 +4076,6 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - cipher-base@1.0.6: - resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} - engines: {node: '>= 0.10'} - cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} @@ -4221,9 +4224,6 @@ packages: engines: {node: '>=0.8'} hasBin: true - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4250,6 +4250,7 @@ packages: crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + deprecated: Active development of CryptoJS has been discontinued. This library is no longer maintained. dag-jose@5.1.1: resolution: {integrity: sha512-9alfZ8Wh1XOOMel8bMpDqWsDT72ojFQCJPtwZSev9qh4f8GoCV9qrJW8jcOUhcstO8Kfm09FHGo//jqiZq3z9w==} @@ -4484,9 +4485,6 @@ packages: resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==} engines: {bun: '>=1', deno: '>=2', node: '>=16'} - ed2curve@0.3.0: - resolution: {integrity: sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ==} - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -5194,10 +5192,6 @@ packages: has-unicode@2.0.1: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} - hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} @@ -5454,10 +5448,6 @@ packages: is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -5932,9 +5922,6 @@ packages: jose@4.15.9: resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} - jose@5.10.0: - resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - jose@6.0.10: resolution: {integrity: sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw==} @@ -6218,9 +6205,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - md5@2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} @@ -6665,6 +6649,7 @@ packages: opensea-js@7.1.18: resolution: {integrity: sha512-cFSwroGwRkb8/FHsNjIwL2qvdve39CKMU6IUKmx+zDfsgVwKQ+7SHEj5YfKEspji5kUPpnfBlNLCAIbRS+pssA==} engines: {node: '>=20.0.0'} + deprecated: This package has been renamed to @opensea/sdk. Install @opensea/sdk instead. optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -6696,6 +6681,14 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + ox@0.11.3: + resolution: {integrity: sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + ox@0.14.5: resolution: {integrity: sha512-HgmHmBveYO40H/R3K6TMrwYtHsx/u6TAB+GpZlgJCoW0Sq5Ttpjih0IZZiwGQw7T6vdW4IAyobYrE2mdAvyF8Q==} peerDependencies: @@ -7246,9 +7239,6 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} - router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -7310,10 +7300,6 @@ packages: scrypt-js@3.0.1: resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - secp256k1@5.0.1: - resolution: {integrity: sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==} - engines: {node: '>=18.0.0'} - secure-compare@3.0.1: resolution: {integrity: sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==} @@ -7380,10 +7366,6 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true - sha.js@2.4.12: resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} engines: {node: '>= 0.10'} @@ -7979,9 +7961,6 @@ packages: peerDependencies: typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x - typeforce@1.18.0: - resolution: {integrity: sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==} - typescript@5.8.2: resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} engines: {node: '>=14.17'} @@ -8159,6 +8138,7 @@ packages: uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uuid@11.1.0: @@ -8171,10 +8151,12 @@ packages: uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true v8-compile-cache-lib@3.0.1: @@ -8243,14 +8225,6 @@ packages: typescript: optional: true - viem@2.38.3: - resolution: {integrity: sha512-By2TutLv07iNHHtWqHHzjGipevYsfGqT7KQbGEmqLco1qTJxKnvBbSviqiu6/v/9REV6Q/FpmIxf2Z7/l5AbcQ==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - viem@2.47.4: resolution: {integrity: sha512-h0Wp/SYmJO/HB4B/em1OZ3W1LaKrmr7jzaN7talSlZpo0LCn0V6rZ5g923j6sf4VUSrqp/gUuWuHFc7UcoIp8A==} peerDependencies: @@ -8360,9 +8334,6 @@ packages: wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - wif@2.0.6: - resolution: {integrity: sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -8457,9 +8428,6 @@ packages: x402-fetch@0.7.0: resolution: {integrity: sha512-HS7v6wsIVrU8TvAGBwRmA3I+ZXbanPraA3OMj90y6Hn1Mej1wAELOK4VpGh6zI8d6w5E464BnGu9o0FE+8DRAA==} - x402@0.6.1: - resolution: {integrity: sha512-9UmeCSsYzFGav5FdVP70VplKlR3V90P0DZ9fPSrlLVp0ifUVi1S9TztvegkmIHE9xTGZ1GWNi+bkne6N0Ea58w==} - x402@0.7.2: resolution: {integrity: sha512-JleP1GmeOP1bEuwzFVtjusL3t5H1PGufROrBKg5pj/MfcGswkBvfB6j5Gm5UeA+kwp0ZmOkkHAqkoHF1WexbsQ==} @@ -8536,6 +8504,9 @@ packages: zod@3.25.56: resolution: {integrity: sha512-rd6eEF3BTNvQnR2e2wwolfTmUTnp70aUTqr0oaGbHifzC3BKJsoV+Gat8vxUMR1hwOKBs6El+qWehrHbCpW6SQ==} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} @@ -8600,10 +8571,6 @@ snapshots: merge-options: 3.0.4 xml2js: 0.6.2 - '@across-protocol/app-sdk@0.2.0(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@across-protocol/app-sdk@0.2.0(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) @@ -8924,26 +8891,6 @@ snapshots: - utf-8-validate - zod - '@base-org/account@2.2.0(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.2)(zod@3.25.56) - preact: 10.24.2 - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - zustand: 5.0.3(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - '@bcoe/v8-coverage@0.2.3': {} '@cfworker/json-schema@4.1.1': {} @@ -9146,83 +9093,6 @@ snapshots: human-id: 4.1.1 prettier: 2.8.8 - '@coinbase/agentkit@0.10.4(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(@types/node@20.17.27)(abitype@1.2.3(typescript@5.8.2)(zod@3.25.56))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(graphql@16.11.0)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@across-protocol/app-sdk': 0.2.0(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@alloralabs/allora-sdk': 0.1.0 - '@base-org/account': 2.2.0(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@coinbase/cdp-sdk': 1.45.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@coinbase/coinbase-sdk': 0.20.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@coinbase/x402': 0.6.4(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@ensofinance/sdk': 2.0.6 - '@jup-ag/api': 6.0.40 - '@privy-io/public-api': 2.18.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@privy-io/server-auth': 1.18.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/spl-token': 0.4.13(@solana/web3.js@1.98.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@vaultsfyi/sdk': 2.1.9(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@x402/evm': 2.7.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@x402/fetch': 2.7.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@x402/svm': 2.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) - '@zerodev/ecdsa-validator': 5.4.5(@zerodev/sdk@5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@zerodev/intent': 0.0.24(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@zerodev/sdk': 5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@zoralabs/coins-sdk': 0.2.8(abitype@1.2.3(typescript@5.8.2)(zod@3.25.56))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@zoralabs/protocol-deployments': 0.6.1 - bs58: 4.0.1 - canonicalize: 2.1.0 - clanker-sdk: 4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - decimal.js: 10.5.0 - ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) - graphql-request: 7.2.0(graphql@16.11.0) - md5: 2.3.0 - opensea-js: 7.1.18(bufferutil@4.0.9)(utf-8-validate@5.0.10) - reflect-metadata: 0.2.2 - sushi: 6.2.1(typescript@5.8.2)(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56) - twitter-api-v2: 1.22.0 - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - zod: 3.25.56 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@solana/sysvars' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/node' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - '@zerodev/webauthn-key' - - abitype - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - graphql - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - ws - '@coinbase/cdp-sdk@1.45.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)': dependencies: '@solana-program/system': 0.10.0(@solana/kit@5.5.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10)) @@ -9245,29 +9115,6 @@ snapshots: - typescript - utf-8-validate - '@coinbase/coinbase-sdk@0.20.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)': - dependencies: - '@scure/bip32': 1.7.0 - abitype: 1.2.3(typescript@5.8.2)(zod@3.25.56) - axios: 1.12.2 - axios-mock-adapter: 1.22.0(axios@1.12.2) - axios-retry: 4.5.0(axios@1.12.2) - bip32: 4.0.0 - bip39: 3.1.0 - decimal.js: 10.5.0 - dotenv: 16.4.7 - ed2curve: 0.3.0 - ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) - jose: 5.10.0 - secp256k1: 5.0.1 - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - transitivePeerDependencies: - - bufferutil - - debug - - typescript - - utf-8-validate - - zod - '@coinbase/wallet-sdk@3.9.3': dependencies: bn.js: 5.2.2 @@ -9302,47 +9149,6 @@ snapshots: - utf-8-validate - zod - '@coinbase/x402@0.6.4(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@coinbase/cdp-sdk': 1.45.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10) - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - x402: 0.6.1(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - zod: 3.25.56 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@solana/sysvars' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - ws - '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -9827,14 +9633,6 @@ snapshots: '@fidm/asn1': 1.0.4 tweetnacl: 1.0.3 - '@gemini-wallet/core@0.2.0(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - '@metamask/rpc-errors': 7.0.2 - eventemitter3: 5.0.1 - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - transitivePeerDependencies: - - supports-color - '@gemini-wallet/core@0.2.0(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: '@metamask/rpc-errors': 7.0.2 @@ -10015,13 +9813,6 @@ snapshots: optionalDependencies: '@types/node': 20.17.27 - '@inquirer/external-editor@1.0.1(@types/node@22.13.14)': - dependencies: - chardet: 2.1.0 - iconv-lite: 0.6.3 - optionalDependencies: - '@types/node': 22.13.14 - '@ipld/dag-cbor@9.2.5': dependencies: cborg: 4.5.8 @@ -10117,41 +9908,6 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2))': - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 20.17.27 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - '@jest/create-cache-key-function@29.7.0': dependencies: '@jest/types': 29.6.3 @@ -11505,7 +11261,7 @@ snapshots: - bufferutil - utf-8-validate - '@privy-io/server-auth@1.18.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': + '@privy-io/server-auth@1.18.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: '@noble/curves': 1.8.1 '@noble/hashes': 1.7.1 @@ -11519,28 +11275,7 @@ snapshots: ts-case-convert: 2.1.0 type-fest: 3.13.1 optionalDependencies: - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - '@privy-io/server-auth@1.18.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': - dependencies: - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@solana/web3.js': 1.98.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.2)(utf-8-validate@5.0.10) - canonicalize: 2.1.0 - dotenv: 16.4.7 - jose: 4.15.9 - node-fetch-native: 1.6.6 - redaxios: 0.5.1 - svix: 1.62.0(encoding@0.1.13) - ts-case-convert: 2.1.0 - type-fest: 3.13.1 - optionalDependencies: - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) + viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) transitivePeerDependencies: - bufferutil - encoding @@ -11638,6 +11373,13 @@ snapshots: react: 18.3.1 react-native: 0.84.1(@babel/core@7.26.10)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@5.0.10) + '@relayprotocol/relay-sdk@6.1.3(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': + dependencies: + axios: 1.13.6(debug@4.4.3) + viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) + transitivePeerDependencies: + - debug + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.22.4)': dependencies: big.js: 6.2.2 @@ -12021,15 +11763,13 @@ snapshots: dependencies: '@solana/kit': 5.5.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@solana-program/token-2022@0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': + '@solana-program/token-2022@0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/sysvars': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) - '@solana-program/token-2022@0.6.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': + '@solana-program/token-2022@0.6.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/sysvars': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) '@solana-program/token@0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: @@ -13278,43 +13018,6 @@ snapshots: '@uniswap/token-lists@1.0.0-beta.33': {} - '@vaultsfyi/sdk@2.1.9(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - x402-fetch: 0.7.0(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@solana/sysvars' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - ws - '@vaultsfyi/sdk@2.1.9(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: x402-fetch: 0.7.0(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -13354,50 +13057,6 @@ snapshots: '@vercel/oidc@3.1.0': {} - '@wagmi/connectors@5.10.0(@wagmi/core@2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56)': - dependencies: - '@base-org/account': 1.1.1(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.56) - '@coinbase/wallet-sdk': 4.3.6(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.56) - '@gemini-wallet/core': 0.2.0(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@wagmi/core': 2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@walletconnect/ethereum-provider': 2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - optionalDependencies: - typescript: 5.8.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - react - - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - '@wagmi/connectors@5.10.0(@wagmi/core@2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@3.25.56)': dependencies: '@base-org/account': 1.1.1(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.56) @@ -13442,21 +13101,6 @@ snapshots: - utf-8-validate - zod - '@wagmi/core@2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.8.2) - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - zustand: 5.0.0(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - optionalDependencies: - '@tanstack/query-core': 5.89.0 - typescript: 5.8.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - '@wagmi/core@2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: eventemitter3: 5.0.1 @@ -14043,11 +13687,11 @@ snapshots: - typescript - utf-8-validate - '@x402/svm@2.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))': + '@x402/svm@2.7.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana-program/compute-budget': 0.11.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@solana-program/token': 0.9.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.6.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + '@solana-program/token-2022': 0.6.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@x402/core': 2.7.0 transitivePeerDependencies: @@ -14120,11 +13764,6 @@ snapshots: rxjs: 7.8.2 undici: 5.29.0 - '@zerodev/ecdsa-validator@5.4.5(@zerodev/sdk@5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - '@zerodev/sdk': 5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@zerodev/ecdsa-validator@5.4.5(@zerodev/sdk@5.4.28(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: '@zerodev/sdk': 5.4.28(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) @@ -14139,23 +13778,6 @@ snapshots: transitivePeerDependencies: - '@zerodev/webauthn-key' - '@zerodev/intent@0.0.24(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - '@zerodev/ecdsa-validator': 5.4.5(@zerodev/sdk@5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@zerodev/multi-chain-ecdsa-validator': 5.4.4(@zerodev/sdk@5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - '@zerodev/sdk': 5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - transitivePeerDependencies: - - '@zerodev/webauthn-key' - - '@zerodev/multi-chain-ecdsa-validator@5.4.4(@zerodev/sdk@5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - '@simplewebauthn/browser': 9.0.1 - '@simplewebauthn/typescript-types': 8.3.4 - '@zerodev/sdk': 5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - merkletreejs: 0.3.11 - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@zerodev/multi-chain-ecdsa-validator@5.4.4(@zerodev/sdk@5.4.28(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)))(@zerodev/webauthn-key@5.4.3(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: '@simplewebauthn/browser': 9.0.1 @@ -14165,11 +13787,6 @@ snapshots: merkletreejs: 0.3.11 viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) - '@zerodev/sdk@5.4.28(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': - dependencies: - semver: 7.7.1 - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - '@zerodev/sdk@5.4.28(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: semver: 7.7.1 @@ -14182,19 +13799,60 @@ snapshots: '@simplewebauthn/types': 12.0.0 viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) - '@zoralabs/coins-sdk@0.2.8(abitype@1.0.8(typescript@5.8.2)(zod@4.3.6))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': + '@zkp2p/cash@0.4.8(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: - '@hey-api/client-fetch': 0.8.4 - '@zoralabs/protocol-deployments': 0.6.1 - abitype: 1.0.8(typescript@5.8.2)(zod@4.3.6) + '@relayprotocol/relay-sdk': 6.1.3(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)) + '@zkp2p/sdk': 0.12.0(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@3.25.76) + viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) + zod: 3.25.76 + optionalDependencies: + react: 18.3.1 + transitivePeerDependencies: + - bufferutil + - debug + - typescript + - utf-8-validate + + '@zkp2p/contracts-v2@0.4.0(ethers@6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typescript@5.8.2)(zod@3.25.76)': + dependencies: + abitype: 1.2.3(typescript@5.8.2)(zod@3.25.76) + ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - typescript + - zod + + '@zkp2p/indexer-schema@0.20.0': {} + + '@zkp2p/sdk@0.12.0(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@3.25.76)': + dependencies: + '@zkp2p/contracts-v2': 0.4.0(ethers@6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typescript@5.8.2)(zod@3.25.76) + '@zkp2p/indexer-schema': 0.20.0 + '@zkp2p/zkp2p-attestation': 2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ox: 0.11.3(typescript@5.8.2)(zod@3.25.76) viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) + optionalDependencies: + react: 18.3.1 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@zkp2p/zkp2p-attestation@2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@peculiar/x509': 1.14.3 + ethers: 6.13.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate - '@zoralabs/coins-sdk@0.2.8(abitype@1.2.3(typescript@5.8.2)(zod@3.25.56))(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))': + '@zoralabs/coins-sdk@0.2.8(abitype@1.0.8(typescript@5.8.2)(zod@4.3.6))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))': dependencies: '@hey-api/client-fetch': 0.8.4 '@zoralabs/protocol-deployments': 0.6.1 - abitype: 1.2.3(typescript@5.8.2)(zod@3.25.56) - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) + abitype: 1.0.8(typescript@5.8.2)(zod@4.3.6) + viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) '@zoralabs/protocol-deployments@0.6.1': {} @@ -14222,11 +13880,6 @@ snapshots: typescript: 5.8.2 zod: 4.3.6 - abitype@1.1.0(typescript@5.8.2)(zod@3.25.56): - optionalDependencies: - typescript: 5.8.2 - zod: 3.25.56 - abitype@1.1.0(typescript@5.8.2)(zod@4.3.6): optionalDependencies: typescript: 5.8.2 @@ -14242,6 +13895,11 @@ snapshots: typescript: 5.8.2 zod: 3.25.56 + abitype@1.2.3(typescript@5.8.2)(zod@3.25.76): + optionalDependencies: + typescript: 5.8.2 + zod: 3.25.76 + abitype@1.2.3(typescript@5.8.2)(zod@4.3.6): optionalDependencies: typescript: 5.8.2 @@ -14470,12 +14128,6 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axios-mock-adapter@1.22.0(axios@1.12.2): - dependencies: - axios: 1.12.2 - fast-deep-equal: 3.1.3 - is-buffer: 2.0.5 - axios-retry@4.5.0(axios@1.12.2): dependencies: axios: 1.12.2 @@ -14594,17 +14246,6 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 - bip32@4.0.0: - dependencies: - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - typeforce: 1.18.0 - wif: 2.0.6 - - bip39@3.1.0: - dependencies: - '@noble/hashes': 1.8.0 - bl@4.1.0: dependencies: buffer: 5.7.1 @@ -14700,12 +14341,6 @@ snapshots: dependencies: base-x: 5.0.1 - bs58check@2.1.2: - dependencies: - bs58: 4.0.1 - create-hash: 1.2.0 - safe-buffer: 5.2.1 - bser@2.1.1: dependencies: node-int64: 0.4.0 @@ -14839,32 +14474,14 @@ snapshots: ci-info@3.9.0: {} - cipher-base@1.0.6: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - cjs-module-lexer@1.4.3: {} - clanker-sdk@4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)): + clanker-sdk@4.1.19(@types/node@20.17.27)(typescript@5.8.2)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)): dependencies: '@openzeppelin/merkle-tree': 1.0.8 abitype: 1.0.8(typescript@5.8.2)(zod@3.25.56) dotenv: 16.4.7 inquirer: 8.2.7(@types/node@20.17.27) - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - zod: 3.25.56 - transitivePeerDependencies: - - '@types/node' - - supports-color - - typescript - - clanker-sdk@4.1.19(@types/node@22.13.14)(typescript@5.8.2)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6)): - dependencies: - '@openzeppelin/merkle-tree': 1.0.8 - abitype: 1.0.8(typescript@5.8.2)(zod@3.25.56) - dotenv: 16.4.7 - inquirer: 8.2.7(@types/node@22.13.14) viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6) zod: 3.25.56 transitivePeerDependencies: @@ -14980,14 +14597,6 @@ snapshots: crc-32@1.2.2: {} - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.6 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 - create-jest@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)): dependencies: '@jest/types': 29.6.3 @@ -15003,21 +14612,6 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - create-require@1.1.1: optional: true @@ -15239,10 +14833,6 @@ snapshots: '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 - ed2curve@0.3.0: - dependencies: - tweetnacl: 1.0.3 - ee-first@1.1.1: {} ejs@3.1.10: @@ -16161,12 +15751,6 @@ snapshots: has-unicode@2.0.1: {} - hash-base@3.1.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - safe-buffer: 5.2.1 - hash.js@1.1.7: dependencies: inherits: 2.0.4 @@ -16393,26 +15977,6 @@ snapshots: transitivePeerDependencies: - '@types/node' - inquirer@8.2.7(@types/node@22.13.14): - dependencies: - '@inquirer/external-editor': 1.0.1(@types/node@22.13.14) - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - figures: 3.2.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 5.4.1 - run-async: 2.4.1 - rxjs: 7.8.2 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - wrap-ansi: 6.2.0 - transitivePeerDependencies: - - '@types/node' - int64-buffer@1.1.0: {} interface-blockstore@5.3.2: @@ -16557,8 +16121,6 @@ snapshots: is-buffer@1.1.6: {} - is-buffer@2.0.5: {} - is-callable@1.2.7: {} is-core-module@2.16.1: @@ -16984,31 +16546,12 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): + jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - '@jest/test-result': 29.7.0 + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - exit: 0.1.2 - import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - - jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2)): - dependencies: - '@babel/core': 7.26.10 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) + babel-jest: 29.7.0(@babel/core@7.26.10) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 @@ -17034,68 +16577,6 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.27)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): - dependencies: - '@babel/core': 7.26.10 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 20.17.27 - ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - jest-config@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): - dependencies: - '@babel/core': 7.26.10 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 22.13.14 - ts-node: 10.9.2(@types/node@22.13.14)(typescript@5.8.2) - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -17323,22 +16804,8 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)): - dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - '@jest/types': 29.6.3 - import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jose@4.15.9: {} - jose@5.10.0: {} - jose@6.0.10: {} jose@6.2.2: {} @@ -17778,12 +17245,6 @@ snapshots: math-intrinsics@1.1.0: {} - md5.js@1.3.5: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 - md5@2.3.0: dependencies: charenc: 0.0.2 @@ -18390,6 +17851,21 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + ox@0.11.3(typescript@5.8.2)(zod@3.25.76): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.8.2)(zod@3.25.76) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - zod + ox@0.14.5(typescript@5.8.2)(zod@3.22.4): dependencies: '@adraffy/ens-normalize': 1.11.1 @@ -18491,21 +17967,6 @@ snapshots: transitivePeerDependencies: - zod - ox@0.9.6(typescript@5.8.2)(zod@3.25.56): - dependencies: - '@adraffy/ens-normalize': 1.11.1 - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.8.2)(zod@3.25.56) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.8.2 - transitivePeerDependencies: - - zod - ox@0.9.6(typescript@5.8.2)(zod@4.3.6): dependencies: '@adraffy/ens-normalize': 1.11.1 @@ -19093,11 +18554,6 @@ snapshots: dependencies: glob: 7.2.3 - ripemd160@2.0.2: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - router@2.2.0: dependencies: debug: 4.4.3 @@ -19179,12 +18635,6 @@ snapshots: scrypt-js@3.0.1: {} - secp256k1@5.0.1: - dependencies: - elliptic: 6.6.1 - node-addon-api: 5.1.0 - node-gyp-build: 4.8.4 - secure-compare@3.0.1: {} seedrandom@3.0.5: {} @@ -19294,11 +18744,6 @@ snapshots: setprototypeof@1.2.0: {} - sha.js@2.4.11: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - sha.js@2.4.12: dependencies: inherits: 2.0.4 @@ -19574,19 +19019,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - sushi@6.2.1(typescript@5.8.2)(viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56): - dependencies: - '@uniswap/token-lists': 1.0.0-beta.33 - big.js: 6.1.1 - date-fns: 3.3.1 - seedrandom: 3.0.5 - tiny-invariant: 1.3.3 - toformat: 2.0.0 - optionalDependencies: - typescript: 5.8.2 - viem: 2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - zod: 3.25.56 - sushi@6.2.1(typescript@5.8.2)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@4.3.6): dependencies: '@uniswap/token-lists': 1.0.0-beta.33 @@ -19762,26 +19194,6 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) - ts-jest@29.3.0(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)))(typescript@5.8.2): - dependencies: - bs-logger: 0.2.6 - ejs: 3.1.10 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.13.14)(ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2)) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.1 - type-fest: 4.38.0 - typescript: 5.8.2 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.26.10 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) - ts-node@10.9.2(@types/node@20.17.27)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -19801,25 +19213,6 @@ snapshots: yn: 3.1.1 optional: true - ts-node@10.9.2(@types/node@22.13.14)(typescript@5.8.2): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.12 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 22.13.14 - acorn: 8.15.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.8.2 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -19963,8 +19356,6 @@ snapshots: typescript: 5.8.2 yaml: 2.7.0 - typeforce@1.18.0: {} - typescript@5.8.2: {} uc.micro@2.1.0: {} @@ -20200,23 +19591,6 @@ snapshots: - utf-8-validate - zod - viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56): - dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.8.2)(zod@3.25.56) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.8.2)(zod@3.25.56) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: '@noble/curves': 1.9.1 @@ -20270,45 +19644,6 @@ snapshots: vlq@1.0.1: {} - wagmi@2.17.0(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56): - dependencies: - '@tanstack/react-query': 5.89.0(react@18.3.1) - '@wagmi/connectors': 5.10.0(@wagmi/core@2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56) - '@wagmi/core': 2.21.0(@tanstack/query-core@5.89.0)(react@18.3.1)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56)) - react: 18.3.1 - use-sync-external-store: 1.4.0(react@18.3.1) - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - optionalDependencies: - typescript: 5.8.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - supports-color - - uploadthing - - utf-8-validate - - zod - wagmi@2.17.0(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@4.3.6))(zod@3.25.56): dependencies: '@tanstack/react-query': 5.89.0(react@18.3.1) @@ -20521,10 +19856,6 @@ snapshots: dependencies: string-width: 4.2.3 - wif@2.0.6: - dependencies: - bs58check: 2.1.2 - word-wrap@1.2.5: {} wrap-ansi@6.2.0: @@ -20576,45 +19907,6 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - x402-fetch@0.7.0(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - x402: 0.7.2(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - zod: 3.25.56 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@solana/sysvars' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - ws - x402-fetch@0.7.0(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): dependencies: viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) @@ -20654,106 +19946,12 @@ snapshots: - utf-8-validate - ws - x402@0.6.1(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - '@scure/base': 1.2.6 - '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - wagmi: 2.17.0(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56) - zod: 3.25.56 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@solana/sysvars' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - ws - - x402@0.7.2(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - '@scure/base': 1.2.6 - '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) - '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/wallet-standard-features': 1.3.0 - '@wallet-standard/app': 1.1.0 - '@wallet-standard/base': 1.1.0 - '@wallet-standard/features': 1.1.0 - viem: 2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56) - wagmi: 2.17.0(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(viem@2.47.4(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.56))(zod@3.25.56) - zod: 3.25.56 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@solana/sysvars' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - ws - x402@0.7.2(@tanstack/query-core@5.89.0)(@tanstack/react-query@5.89.0(react@18.3.1))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): dependencies: '@scure/base': 1.2.6 '@solana-program/compute-budget': 0.8.0(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@solana-program/token': 0.5.1(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)) + '@solana-program/token-2022': 0.4.2(@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@solana/kit': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-standard-features': 1.3.0 @@ -20864,6 +20062,8 @@ snapshots: zod@3.25.56: {} + zod@3.25.76: {} + zod@4.3.6: {} zustand@5.0.0(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): From e07535c1f6d9d36884f85e7a6f6a0f76b5943ae6 Mon Sep 17 00:00:00 2001 From: Andrew Wilkinson Date: Fri, 14 Aug 2026 14:16:32 +0100 Subject: [PATCH 2/2] fix: preserve Peer Cash transaction recovery --- .../peerCash/peerCashActionProvider.test.ts | 129 ++++++++++++- .../peerCash/peerCashActionProvider.ts | 173 ++++++++++++++++-- .../src/action-providers/peerCash/schemas.ts | 3 +- 3 files changed, 282 insertions(+), 23 deletions(-) diff --git a/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts index 86b10906a..1f5438704 100644 --- a/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts +++ b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.test.ts @@ -124,9 +124,11 @@ describe("PeerCashActionProvider", () => { .fn() .mockReturnValue({ protocolFamily: "evm", networkId: "base-mainnet", chainId: "8453" }), sendTransaction: jest.fn().mockResolvedValue("0xhash1" as `0x${string}`), - waitForTransactionReceipt: jest - .fn() - .mockResolvedValue({ status: "success", transactionHash: "0xhash1", logs: [] }), + waitForTransactionReceipt: jest.fn().mockImplementation(async txHash => ({ + status: "success", + transactionHash: txHash, + logs: [], + })), } as unknown as jest.Mocked; provider = new PeerCashActionProvider(); }); @@ -403,6 +405,77 @@ describe("PeerCashActionProvider", () => { expect(mockClient.finalizePreparedCashout).not.toHaveBeenCalled(); }); + it("preserves the submitted hash when a receipt lookup fails", async () => { + mockWallet.waitForTransactionReceipt.mockRejectedValueOnce(new Error("RPC timeout")); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain("approve transaction for the cash-out was submitted"); + expect(response).toContain("0xhash1"); + expect(response).toContain("Do not submit the operation again"); + expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(1); + }); + + it("treats an unrecognized receipt status as an unknown outcome", async () => { + mockWallet.waitForTransactionReceipt.mockResolvedValueOnce({ + transactionHash: "0xbase1", + logs: [], + }); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain("wallet submission hash: 0xhash1"); + expect(response).toContain("receipt could not be confirmed"); + expect(mockWallet.sendTransaction).toHaveBeenCalledTimes(1); + }); + + it("preserves earlier confirmed hashes when a later receipt lookup fails", async () => { + mockWallet.waitForTransactionReceipt + .mockResolvedValueOnce({ status: "success", transactionHash: "0xhash1", logs: [] }) + .mockRejectedValueOnce(new Error("RPC timeout")); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain("createDeposit transaction for the cash-out was submitted"); + expect(response).toContain("0xhash2"); + expect(response).toContain("Earlier confirmed steps: approve: 0xhash1"); + expect(response).toContain("Do not submit the operation again"); + }); + + it("warns against retrying when receipt finalization cannot recover the order id", async () => { + mockClient.finalizePreparedCashout.mockImplementation(() => { + throw new Error("missing event"); + }); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain( + "createDeposit transaction confirmed (Base transaction hash: 0xhash2)", + ); + expect(response).toContain("Do not create another cash-out"); + expect(response).toContain("list_orders"); + }); + it("keeps the deposit and points at configure_access_policy when the policy fails", async () => { mockClient.prepare.mockResolvedValue({ ...PREPARE_RESULT, accessPolicyRequired: true }); mockClient.prepareAccessPolicy.mockReturnValue(MOCK_TX); @@ -424,6 +497,50 @@ describe("PeerCashActionProvider", () => { expect(response).toContain("configure_access_policy"); }); + it("does not retry an access policy whose receipt outcome is unknown", async () => { + mockClient.prepare.mockResolvedValue({ ...PREPARE_RESULT, accessPolicyRequired: true }); + mockClient.prepareAccessPolicy.mockReturnValue(MOCK_TX); + mockWallet.waitForTransactionReceipt + .mockResolvedValueOnce({ status: "success", transactionHash: "0xhash1", logs: [] }) + .mockResolvedValueOnce({ status: "success", transactionHash: "0xhash2", logs: [] }) + .mockRejectedValueOnce(new Error("RPC timeout")); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(response).toContain(`Created Peer Cash cash-out order ${MOCK_DEPOSIT_ID}`); + expect(response).toContain( + "access policy transaction was submitted (wallet submission hash: 0xhash3)", + ); + expect(response).toContain("Do not create another cash-out or resubmit the policy"); + expect(response).not.toContain("configure_access_policy"); + }); + + it("uses the containing Base transaction hash for smart-wallet confirmations", async () => { + mockWallet.waitForTransactionReceipt.mockImplementation(async txHash => ({ + status: "success", + transactionHash: txHash === "0xhash1" ? "0xbase1" : "0xbase2", + logs: [{ address: "0x3333333333333333333333333333333333333333" }], + })); + + const response = await provider.cashout(mockWallet, { + amountUsdc: "250", + platform: "venmo", + currency: "USD", + payee: "@alice", + }); + + expect(mockClient.finalizePreparedCashout).toHaveBeenCalledWith( + expect.objectContaining({ transactionHash: "0xbase2" }), + ); + expect(response).toContain("approve: 0xbase1 (wallet submission: 0xhash1)"); + expect(response).toContain("createDeposit: 0xbase2 (wallet submission: 0xhash2)"); + }); + it("maps CashErrors from prepare", async () => { mockClient.prepare.mockRejectedValue( new CashError({ @@ -675,6 +792,7 @@ describe("PeerCashActionProvider", () => { expect(EstimateSchema.safeParse({ amountUsdc: "250", currency: "USD" }).success).toBe(true); expect(EstimateSchema.safeParse({ amountUsdc: "12.34", currency: "USD" }).success).toBe(true); expect(EstimateSchema.safeParse({ amountUsdc: "-5", currency: "USD" }).success).toBe(false); + expect(EstimateSchema.safeParse({ amountUsdc: "0", currency: "USD" }).success).toBe(false); expect(EstimateSchema.safeParse({ amountUsdc: "1.1234567", currency: "USD" }).success).toBe( false, ); @@ -702,5 +820,10 @@ describe("PeerCashActionProvider", () => { true, ); }); + + it("rejects malformed deposit ids", () => { + expect(WithdrawSchema.safeParse({ depositId: MOCK_DEPOSIT_ID }).success).toBe(true); + expect(WithdrawSchema.safeParse({ depositId: "bogus" }).success).toBe(false); + }); }); }); diff --git a/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts index 5cfbc1caa..bc2e60e5d 100644 --- a/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts +++ b/typescript/agentkit/src/action-providers/peerCash/peerCashActionProvider.ts @@ -93,6 +93,21 @@ interface TransactionReceiptLike { logs?: unknown; } +/** + * Formats a confirmed step using the containing Base transaction hash when a + * smart-wallet receipt exposes one, while retaining the wallet submission id. + * + * @param step - The confirmed prepared-plan step. + * @returns A compact step and transaction identifier. + */ +function formatSubmittedStep(step: SubmittedStep): string { + const transactionHash = step.receipt.transactionHash; + if (transactionHash && transactionHash !== step.txHash) { + return `${step.kind}: ${transactionHash} (wallet submission: ${step.txHash})`; + } + return `${step.kind}: ${step.txHash}`; +} + /** * Thrown when a submitted transaction of a prepared plan reverted on-chain. */ @@ -112,6 +127,50 @@ class StepRevertedError extends Error { } } +/** + * Thrown when a transaction was submitted but its receipt could not be + * determined. The hash is a recovery handle: callers must inspect it before + * deciding whether it is safe to submit another transaction. + */ +class StepOutcomeUnknownError extends Error { + /** + * Constructor for the StepOutcomeUnknownError class. + * + * @param step - The step kind whose receipt could not be determined. + * @param txHash - The submitted transaction hash. + * @param completed - Earlier steps that were already confirmed. + * @param cause - The receipt lookup error. + */ + constructor( + readonly step: string, + readonly txHash: `0x${string}`, + readonly completed: SubmittedStep[], + readonly cause: unknown, + ) { + super(`The outcome of ${step} is unknown (hash: ${txHash})`); + this.name = "StepOutcomeUnknownError"; + } +} + +/** + * Formats a submitted transaction whose receipt could not be determined. + * + * @param operation - The operation containing the uncertain step. + * @param error - The uncertain step and its recovery metadata. + * @returns A recovery-safe message that prevents blind resubmission. + */ +function describeUnknownOutcome(operation: string, error: StepOutcomeUnknownError): string { + const completed = error.completed.length + ? ` Earlier confirmed steps: ${error.completed.map(formatSubmittedStep).join(", ")}.` + : ""; + return ( + `Error: the ${error.step} transaction for ${operation} was submitted (wallet submission ` + + `hash: ${error.txHash}), but its receipt could not be confirmed.${completed} Do not submit ` + + `the operation again. Resolve that submission through the connected wallet provider or its ` + + `bundler; if it produced a Base transaction, inspect that transaction and check the order state.` + ); +} + /** * Checks whether a wallet provider receipt reports an on-chain failure. * Viem receipts report "success" or "reverted"; CDP user operation receipts @@ -125,6 +184,18 @@ function isRevertedReceipt(receipt: TransactionReceiptLike | null | undefined): return status === "reverted" || status === "failed" || status === 0 || status === "0x0"; } +/** + * Checks whether a wallet provider receipt explicitly reports confirmation. + * Unknown receipt shapes are treated as uncertain rather than successful. + * + * @param receipt - The receipt returned by waitForTransactionReceipt. + * @returns True when the receipt carries a known success marker. + */ +function isSuccessfulReceipt(receipt: TransactionReceiptLike | null | undefined): boolean { + const status = receipt?.status; + return status === "success" || status === "complete" || status === 1 || status === "0x1"; +} + /** * Formats an error from a Peer Cash operation into an actionable message. * CashErrors carry a stable code, whether the operation is retryable, a @@ -314,6 +385,9 @@ Important notes: try { submitted = await this.#submitPreparedPlan(walletProvider, prepared.txs, prepared.steps); } catch (error) { + if (error instanceof StepOutcomeUnknownError) { + return describeUnknownOutcome("the cash-out", error); + } if (error instanceof StepRevertedError) { return ( `Error: the ${error.step} transaction of the cash-out reverted ` + @@ -327,13 +401,30 @@ Important notes: if (!depositStep) { return "Error: the prepared cash-out plan had no createDeposit step; no order was created."; } - const result = this.#client.finalizePreparedCashout({ - // Smart wallet providers return user operation receipts; their - // transactionHash is the containing transaction that holds the logs. - transactionHash: depositStep.receipt.transactionHash ?? depositStep.txHash, - status: "success", - logs: (depositStep.receipt.logs ?? []) as PreparedCashoutReceipt["logs"], - }); + let result; + try { + result = this.#client.finalizePreparedCashout({ + // Smart wallet providers return user operation receipts; their + // transactionHash is the containing transaction that holds the logs. + transactionHash: depositStep.receipt.transactionHash ?? depositStep.txHash, + status: "success", + logs: (depositStep.receipt.logs ?? []) as PreparedCashoutReceipt["logs"], + }); + } catch (error) { + const transactionHash = depositStep.receipt.transactionHash; + const recoveryHandle = transactionHash + ? `Base transaction hash: ${transactionHash}` + : `wallet submission hash: ${depositStep.txHash}`; + const recoveryInstruction = transactionHash + ? "inspect that transaction on Base" + : "resolve that submission through the connected wallet provider or its bundler"; + return ( + `The createDeposit transaction confirmed (${recoveryHandle}), but the ` + + `cash-out order id could not be derived from its receipt: ${String(error)}. The USDC ` + + `may already be in escrow. Do not create another cash-out; ${recoveryInstruction} and ` + + `use list_orders for the connected wallet to recover the order.` + ); + } let accessPolicyNote = ""; if (prepared.accessPolicyRequired) { @@ -341,6 +432,17 @@ Important notes: const policyTxHash = await this.#submitAccessPolicy(walletProvider, result.depositId); accessPolicyNote = ` The restricted-platform access policy was configured (transaction: ${policyTxHash}).`; } catch (error) { + if (error instanceof StepOutcomeUnknownError) { + return ( + `Created Peer Cash cash-out order ${result.depositId} for ${args.amountUsdc} USDC ` + + `on ${args.platform} (deposit transaction: ${result.txHash}). The access policy ` + + `transaction was submitted (wallet submission hash: ${error.txHash}), but its ` + + `receipt could not be ` + + `confirmed. The USDC is already in escrow. Do not create another cash-out or ` + + `resubmit the policy. Resolve that submission through the connected wallet provider ` + + `or its bundler first.` + ); + } const reason = error instanceof StepRevertedError ? `the access policy transaction reverted (hash: ${error.txHash})` @@ -355,7 +457,7 @@ Important notes: } } - const steps = submitted.map(step => `${step.kind}: ${step.txHash}`).join(", "); + const steps = submitted.map(formatSubmittedStep).join(", "); return ( `Created Peer Cash cash-out order ${result.depositId} for ${args.amountUsdc} USDC on ` + `${args.platform} (transactions: ${steps}).${accessPolicyNote} The order is now ` + @@ -473,13 +575,16 @@ Important notes: prepared.txs, prepared.steps, ); - const steps = submitted.map(step => `${step.kind}: ${step.txHash}`).join(", "); + const steps = submitted.map(formatSubmittedStep).join(", "); const summary = args.amountUsdc !== undefined ? `Withdrew ${args.amountUsdc} USDC from order ${args.depositId}` : `Closed order ${args.depositId} and withdrew the remaining USDC`; return `${summary} (transactions: ${steps}).`; } catch (error) { + if (error instanceof StepOutcomeUnknownError) { + return describeUnknownOutcome("the withdrawal", error); + } if (error instanceof StepRevertedError) { return ( `Error: the ${error.step} transaction of the withdrawal reverted ` + @@ -521,9 +626,12 @@ The added funds pay out to the same payee and fill at the same live oracle marke prepared.txs, prepared.steps, ); - const steps = submitted.map(step => `${step.kind}: ${step.txHash}`).join(", "); + const steps = submitted.map(formatSubmittedStep).join(", "); return `Added ${args.amountUsdc} USDC to order ${args.depositId} (transactions: ${steps}).`; } catch (error) { + if (error instanceof StepOutcomeUnknownError) { + return describeUnknownOutcome("the top up", error); + } if (error instanceof StepRevertedError) { return ( `Error: the ${error.step} transaction of the top up reverted (hash: ${error.txHash}). ` + @@ -567,6 +675,9 @@ Important notes: `Intent signaling is now restricted to the required buyer groups.` ); } catch (error) { + if (error instanceof StepOutcomeUnknownError) { + return describeUnknownOutcome("the access policy update", error); + } if (error instanceof StepRevertedError) { return ( `Error: the access policy transaction reverted (hash: ${error.txHash}). Inspect that ` + @@ -620,11 +731,24 @@ Important notes: data: tx.data, value: tx.value, }); - const receipt = (await walletProvider.waitForTransactionReceipt( - txHash, - )) as TransactionReceiptLike; + let receipt: TransactionReceiptLike; + try { + receipt = (await walletProvider.waitForTransactionReceipt( + txHash, + )) as TransactionReceiptLike; + } catch (error) { + throw new StepOutcomeUnknownError(kind, txHash, [...submitted], error); + } if (isRevertedReceipt(receipt)) { - throw new StepRevertedError(kind, txHash); + throw new StepRevertedError(kind, receipt.transactionHash ?? txHash); + } + if (!isSuccessfulReceipt(receipt)) { + throw new StepOutcomeUnknownError( + kind, + txHash, + [...submitted], + new Error(`Unrecognized receipt status: ${String(receipt.status)}`), + ); } submitted.push({ kind, txHash, receipt }); } @@ -649,13 +773,24 @@ Important notes: data: policyTx.data, value: policyTx.value, }); - const receipt = (await walletProvider.waitForTransactionReceipt( - txHash, - )) as TransactionReceiptLike; + let receipt: TransactionReceiptLike; + try { + receipt = (await walletProvider.waitForTransactionReceipt(txHash)) as TransactionReceiptLike; + } catch (error) { + throw new StepOutcomeUnknownError("accessPolicy", txHash, [], error); + } if (isRevertedReceipt(receipt)) { - throw new StepRevertedError("accessPolicy", txHash); + throw new StepRevertedError("accessPolicy", receipt.transactionHash ?? txHash); + } + if (!isSuccessfulReceipt(receipt)) { + throw new StepOutcomeUnknownError( + "accessPolicy", + txHash, + [], + new Error(`Unrecognized receipt status: ${String(receipt.status)}`), + ); } - return txHash; + return receipt.transactionHash ?? txHash; } } diff --git a/typescript/agentkit/src/action-providers/peerCash/schemas.ts b/typescript/agentkit/src/action-providers/peerCash/schemas.ts index 36865c95d..2d40f581a 100644 --- a/typescript/agentkit/src/action-providers/peerCash/schemas.ts +++ b/typescript/agentkit/src/action-providers/peerCash/schemas.ts @@ -10,6 +10,7 @@ import { z } from "zod"; const usdcAmount = z .string() .regex(/^\d+(\.\d{1,6})?$/, "Must be a decimal USDC amount with at most 6 decimal places") + .refine(value => /[1-9]/.test(value), "Must be greater than zero") .describe("The USDC amount in whole units, e.g. '250' or '12.34'"); const currencyCode = z @@ -19,7 +20,7 @@ const currencyCode = z const depositId = z .string() - .min(1) + .regex(/^0x[a-fA-F0-9]{40}_\d+$/, "Must be a Peer Cash deposit id") .describe("The deposit id of the cash-out order, as returned by the cashout action"); /**