Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Add Peer Cash action provider by ADWilkinson · Pull Request #1438 · coinbase/agentkit · GitHub
Skip to content

Add Peer Cash action provider - #1438

Open
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider
Open

Add Peer Cash action provider#1438
ADWilkinson wants to merge 3 commits into
coinbase:mainfrom
ADWilkinson:feat/peer-cash-action-provider

Conversation

@ADWilkinson

@ADWilkinsonADWilkinson commented Aug 13, 2026

Copy link
Copy Markdown

Description

Adds a Peer Cash action provider to the TypeScript AgentKit package.

What is Peer Cash

Peer Cash is our offramp SDK for the Peer P2P protocol (peer.xyz), live in production today. An agent's Base USDC becomes fiat in the user's payment app: Venmo, Revolut, Wise, Zelle and more. It is non-custodial: funds only ever sit in the user's wallet or the protocol escrow contract, and orders fill at the live Chainlink rate with zero spread. No API key is required.

What this PR adds

A peerCash action provider with eight actions:

  • estimate: fiat amount for a USDC amount at the live oracle rate. It is an estimate, not a locked quote. The binding rate resolves when a buyer fills.
  • capabilities: payout platforms and their currencies, payee format hints, amount bounds, optional 30 day fill stats.
  • cashout: moves USDC into the escrow contract and creates the order. Handles the follow-up access policy transaction for Venmo, Cash App and PayPal automatically.
  • order_status: lifecycle state by deposit id, with a plain language explanation and the allowed next actions.
  • list_orders: orders owned by a wallet.
  • withdraw: the single unwind verb. Partial with an amount, full close without. Expired buyer intents get pruned automatically.
  • top_up: add USDC to a live order.
  • configure_access_policy: recovery only. Used when a cashout created the deposit but the policy transaction failed, so the agent never doubles up a cash-out.

Plus the provider README, 43 focused unit tests, the package README table entry, a changeset, and the @zkp2p/cash dependency.

Design notes

  • Wallet abstraction: the SDK's signed path wants a viem WalletClient, which an EvmWalletProvider is not guaranteed to expose (CDP server and smart wallets sign remotely). So the provider uses the SDK's unsigned prepare path and submits each returned transaction through walletProvider.sendTransaction in step order, waiting for each receipt. Every agentkit wallet provider works unchanged and signing never leaves your wallet abstraction.
  • Network gating: supportsNetwork is Base mainnet only. The preproduction and staging environments also settle on Base mainnet with separate contracts, so the gate holds for all three.
  • Errors: the SDK throws typed errors with a stable code, a retryable flag and a remediation sentence. The provider surfaces all of it so the agent can recover instead of guessing. A reverted step is reported with its step kind and hash, and a failed access policy points at the recovery action instead of letting the agent create a second deposit for the same funds.
  • @zkp2p/cash declares node >= 22, same as this repo's dev requirement. The unit tests mock the SDK, so the node 18/20 CI matrix is unaffected.
  • The lockfile regen also drops a stale examples/register importer that no longer exists in the tree. Any pnpm install reproduces that, and the check-package-lock job wants it committed.

Config

constprovider=peerCashActionProvider({environment: "production",// default; also "preproduction" | "staging"referralCode: "ABC123",// optional, earns the integration sharereferrer: "acme-app",// optional, analytics-only attributionrpcUrl: "https://mainnet.base.org",// optional Base RPC override});

No API keys required. The provider works with zero config.

How integrators earn

referralCode is the six character 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 separate: analytics-only attribution, no revenue share.

Tests

From typescript/:

  • pnpm install: lockfile stable, no diff after install
  • pnpm run test (turbo, all packages): 11/11 tasks pass

From typescript/agentkit:

  • pnpm test: 61 suites, 900 tests pass on the initial integration revision
  • 43 focused Peer Cash tests pass on the current head
  • pnpm run lint: pass
  • pnpm run format:check: pass
  • pnpm run check: pass
  • pnpm run build: pass

Live read-only smoke test of the built provider against production (no wallet or keys needed):

Network: Base Mainnet
Setup: production environment, read actions only
estimate 250 USDC -> EUR:
Approximately 216.8 EUR for 250 USDC at the current oracle rate of 0.8672161926607495
(zero spread). This is not a locked quote; the binding rate resolves when a buyer fills.
Estimated time to first fill: Usually starts in about 1 hr.
estimate with an unsupported currency:
Error (ORACLE_UNSUPPORTED_CURRENCY) while estimating the cash-out: XXX has no live
Chainlink oracle feed; Peer Cash is market-rate only. Remediation: Pick a currency
listed in capabilities() - each one is priced by a live oracle feed. Retryable: no.
capabilities with fill stats:
"revolut:EUR": { "fills": 518, "medianFillSeconds": 3142 }, ...

The mutating actions (cashout, withdraw, top_up, configure_access_policy) are covered by unit tests against a mocked SDK and wallet provider, including transaction order, reverted steps and the access policy failure path.

Checklist

  • Added documentation to all relevant README.md files
  • Added a changelog entry

Links

SDK → https://www.npmjs.com/package/@zkp2p/cash
Docs → https://docs.peer.xyz/developer/peer-cash
Prompt → https://peer.xyz/cash-sdk
Builders Club → https://t.me/zk_p2p/167174

Support

Support is available through the Builders Club above or @AndrewWilkinson on X.

@cb-heimdall

cb-heimdall commented Aug 13, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/2
Denominator calculation
Show calculation
1 if user is bot0
1 if user is external0
2 if repo is sensitive0
From .codeflow.yml1
Additional review requirements
Show calculation
Max0
0
From CODEOWNERS0
Global minimum0
Max 1
1
1 if commit is unverified1
Sum2

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation action provider New action provider typescript labels Aug 13, 2026
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from d5271e4 to 16ad580CompareAugust 13, 2026 10:11
@ADWilkinson
ADWilkinsonforce-pushed the feat/peer-cash-action-provider branch from f3f5d01 to e07535cCompareAugust 14, 2026 13:20
@ADWilkinson

Copy link
Copy Markdown
Author

Quality review update:

  • hardened transaction recovery so receipt timeouts preserve submitted hashes and never trigger a blind duplicate cash-out
  • preserved confirmed prior steps across partial failures, including access-policy recovery after deposit confirmation
  • distinguished smart-wallet submission hashes from Base transaction hashes and record the mined Base hash when the receipt exposes it
  • tightened deposit ID and positive-amount validation

Current validation: 43 focused tests pass, plus TypeScript, ESLint, and Prettier. Both commits are GitHub-verified. The PR is mergeable; the remaining gates are maintainer review and the external StepSecurity check.

@ADWilkinson

Copy link
Copy Markdown
Author

Updated to current main in 7acc650. Re-verified the merged head: all 43 focused Peer Cash tests pass; targeted ESLint and Prettier checks pass; TypeScript compilation with tsc --noEmit passes; git diff --check passes. The branch is now current and the remaining gates are maintainer review / Heimdall.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providerdocumentationImprovements or additions to documentationtypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@ADWilkinson@cb-heimdall