Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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" + '
feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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('^' + ".*" + ' feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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('^' + ".*" + ' feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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" + ' feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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('^' + ".*" + ' feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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('^' + ".*" + ' feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@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); } })(); })(); feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet by osr21 · Pull Request #1333 · coinbase/agentkit · GitHub
Skip to content

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet - #1333

Open
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider
Open

feat: add BasePay action provider — gasless USDC, batch pay, escrow, subscriptions on Base Mainnet#1333
osr21 wants to merge 10 commits into
coinbase:mainfrom
osr21:feat/basepay-action-provider

Conversation

@osr21

@osr21osr21 commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR adds BasePay as a community action provider for AgentKit, giving AI agents five USDC payment primitives on Base Mainnet with no additional dependencies.

Actions added

ActionDescription
basepay_send_usdcDirect USDC transfer (agent pays ETH gas)
basepay_send_usdc_gaslessEIP-3009 relay — no ETH needed by the agent
basepay_batch_pay_usdcPay up to 200 recipients atomically
basepay_create_escrowTime-lock USDC for a beneficiary
basepay_subscribeOn-chain recurring USDC payment

How gasless works

The agent signs an EIP-3009 TransferWithAuthorization typed message (no on-chain tx). The BasePay relay submits it to USDC.transferWithAuthorization(), paying the ETH gas. This means agents can send USDC with zero ETH balance — a critical unlock for autonomous agent wallets.

Verified contracts (Base Mainnet)

ContractAddress
BatchPayV20xe40d…c68
EscrowV20x1eb2…499
SubscriptionManagerV20x1019…421

Usage

import{AgentKit}from"@coinbase/agentkit";import{basePayActionProvider}from"./action-providers/basepay";constagentKit=awaitAgentKit.from({
walletProvider,actionProviders: [basePayActionProvider()],});

Or via the standalone npm package:

npm install basepay-agentkit @coinbase/agentkit viem zod
import{basePayActionProvider}from"basepay-agentkit";

Self-hosting the relay

The relay is open-source (github.com/osr21/basepay) and requires only a funded EOA (ETH on Base) to operate. Configurable via basePayActionProvider({ relayUrl: "https://your-relay.example.com" }).

No new dependencies

The provider uses only packages already in the AgentKit dependency graph (viem, zod). The relay call uses native fetch.


Live dApp: https://base-pay.replit.app
npm package: https://www.npmjs.com/package/basepay-agentkit
Contracts + source: https://github.com/osr21/basepay

@osr21
osr21 requested a review from murrlincoln as a code ownerJune 20, 2026 17:53
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown

🟡 Heimdall Review Status

RequirementStatusMore Info
Reviews 🟡 0/1
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

@osr21

Copy link
Copy Markdown
Author

Hi @murrlincoln 👋 — I've just pushed a unit test file (basepayActionProvider.test.ts) to bring the PR in line with the pattern used by other action providers (e.g. basename).

What the tests cover:

  • Schema validation for all five action inputs (valid, invalid address, out-of-range values, edge cases)
  • sendUsdc — success path + error handling
  • batchPayUsdc — approve+batchSend when allowance is zero, approve-skip when sufficient, revert error
  • createEscrow — approve+create, unlock-duration label, error path
  • subscribe — approve+subscribe, weekly/monthly interval labels, error path
  • sendUsdcGasless — EIP-3009 typed-data signing, relay success, missing signTypedData, relay error, relay fetch throw

There's also been active design discussion happening in issue #1141 around the policy hook extension — six external contributors have weighed in with concrete specs. Happy to address any review feedback quickly. Let me know if anything else is needed before merge!

osr21 added 5 commits June 29, 2026 20:47
Fix 1: pending.add(ref) inside checkPolicy before returning; closes race
window in two-set pattern where concurrent calls both passed the duplicate
check before either had added to pending.
Fix 2: remove duplicate consumed.add in sendUsdcGasless; the add before
signTypedData (the authority boundary) is kept, the post-relay add removed.
Fix 3: re-derive recipient_allocation_hash at execution boundary in
batchPayUsdc before ensureAllowance; closes TOCTOU window between
policy evaluation and execution.
Fix 4: replace home-grown canonicalize with the canonicalize npm package
(RFC 8785 JCS); action_context_hash values now compatible with the
argenum-core conformance fixture.
Fix 5: check receipt.status on all four waitForTransactionReceipt call
sites; status: "reverted" produces [failed] not [executed].
Fix 6: sendUsdcGasless returns [relay_confirmed] after relay HTTP 200;
relay-submitted is not the same as on-chain-confirmed.
Fix 7: two-layer execution-boundary test matrix — Layer 1 (authority gate,
before first irreversible op) and Layer 2 (settlement outcome, after
chain/relay result) for all five actions plus subscription authority plane.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action providerNew action providertypescript

Development

Successfully merging this pull request may close these issues.

2 participants

@osr21@cb-heimdall