feat: Peer Cash actions for non-custodial USDC to fiat on Base - #33
feat: Peer Cash actions for non-custodial USDC to fiat on Base#33ADWilkinson wants to merge 2 commits into
Conversation
|
Thanks, reviewed the code (incl. client.ts and prepareCashout.ts), and the prepare-only shape is exactly right: no keys touched, custody preserved, clean pass-through. Can't merge as-is, but it's close. Two changes needed:
Two non-blocking decisions to note on the thread: whether this ships in agentkit-core or as its own package (leaning separate, given 1.0 dep pruning), and confirming the 0.1.0 → 1.0.0 bump + lockfile changes belong in this PR. Do the two changes above and it's good to merge. |
|
Implemented both blockers in 8ce25b2:
Canonical address source: the checked-in Base deployment artifacts in https://github.com/zkp2p/zkp2p-contracts/tree/main/deployments/base ( Verification on the pushed head:
On the two non-blocking points: I kept this in |
Implements #32. Adds eight Peer Cash actions so an agent can turn its Base USDC into fiat.
Peer Cash is an offramp protocol on Base. The agent's wallet is the maker: its USDC becomes a protocol-held order, a buyer pays fiat to the agent's own Venmo, Revolut, Wise, Zelle, PayPal, Cash App, Chime, or Monzo handle and proves the payment with TEE-TLS, and the escrow releases the USDC at the live Chainlink oracle rate with zero spread.
@zkp2p/cash, MIT, https://github.com/zkp2p/peer-cash#32 asks whether you want prepare-only or an additional signing verb. This PR is the prepare-only shape. If you would rather have a one-shot
peer_cash_cashoutthat submits throughwallet.sendTransaction, say so on the issue and I will add it here.Custody
Every mutating verb returns UNSIGNED
{ to, data, value, chainId }forsend_transactionto submit. No action in this PR accepts, reads, derives, or stores a private key, and@zkp2p/cashexposes no signing path in the surface these actions use. The order belongs to whichever address submits the transactions.Files
agentkit-core/src/actions/PeerCashAction/client.tscapabilities.tspeer_cash_capabilitiesestimate.tspeer_cash_estimateprepareCashout.tspeer_cash_prepare_cashout[approve, createDeposit]prepareAccessPolicy.tspeer_cash_prepare_access_policyorder.tspeer_cash_orderorders.tspeer_cash_ordersprepareTopUp.tspeer_cash_prepare_topup[approve, addFunds]prepareWithdraw.tspeer_cash_prepare_withdrawindex.tsPEER_CASH_ACTIONSAll eight are
walletOptional: trueandsmartAccountRequired: false, so they run in platform mode, self-custody mode, and with no wallet configured.peer_cash_ordersis the only one that reads the wallet, and only to default the address.Also changed:
agentkit-core/src/actions/index.ts: registersPEER_CASH_ACTIONS.agentkit-core/package.json: adds@zkp2p/cash, and runs the new smoke test fromtest:smoke.agentkit-core/tsconfig.json:"target": "es2022". The neweroxthat viem resolves to ships.tssources needingString.replaceAlland theErrorcauseoption, sobun run checkfails ates2020. Scoped to this file rather thantsconfig.base.json.agentkit-core/test/peer-cash.smoke.mjs: new, in the style ofplatform.smoke.mjs.bun.lock.Test plan
bun run check: exit 0bun run build: exit 0biome lintandbiome checkon the new directory: cleanbun run lint: same 30 pre-existing errors asmain, none inPeerCashActionbun run test:smoke: bothPLATFORM SMOKEandPEER CASH SMOKEpassPEER_CASH_SMOKE_LIVE=1 node test/peer-cash.smoke.mjs: passes against Peer productionThe new smoke test is offline by default, covering registration, wallet-optional dispatch, argument schemas, and the typed error surface.
PEER_CASH_SMOKE_LIVE=1adds production reads and one unsigned cash-out plan;PEER_CASH_SMOKE_ORDER_IDadds order and list reads. It never signs or broadcasts.Live results from
getAllAgentkitActions()with no wallet configured: discovery returned 8 payout platforms across 13 currencies on chain 8453 at 0 bps spread; a 250 USDC estimate returned 215.67 EUR at 0.8627 with a 40 minute ETA;peer_cash_prepare_cashoutreturned[approve, createDeposit]both withchainId: 8453;peer_cash_prepare_topupreturned[approve, addFunds];peer_cash_prepare_withdrawreturned a singlewithdrawDeposit;peer_cash_prepare_access_policyreturned one transaction; a nonexistent order id returnedError: Peer Cash order failed. [ORDER_NOT_FOUND] ... This error is retryable.Notes
supportedChainswith USDC intokenMappings. Prepared transactions carrychainId: 8453, so submitting them needs an agent configured on Base. The read actions work on any chain.referrer: "0xgasless-agentkit", an ERC-8021 analytics marker appended to the calldata suffix beside thepeer-cashmarker the SDK adds regardless. It carries no funds and grants no permissions. Happy to drop it.PEER_CASH_RPC_URLoverrides the public Base RPC, which is rate limited.PEER_CASH_REFERRAL_CODEis the operator's own six-character Peer code. Both are optional and read the same waysxt.tsreadsSXT_API_KEY.