Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

CdpEvmWalletProvider.sendTransaction omits idempotencyKey, which the CDP SDK accepts — an agent retry after a lost response sends the transfer twice (cdpEvmWalletProvider.ts:195)

Open
#1,483 7 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@Baophan00 is already working on this.

Since Oct 1, 2026.

  • #1489 by @kutluhaneth46 — closed without merging
  • #1504 by @scientivan — open
  • #1530 by @Baophan00 — open

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
typescript

Research direction

Read typescript/agentkit/src/wallet-providers/cdpEvmWalletProvider.ts at sendTransaction and nativeTransfer, then compare the delegation in cdpSmartWalletProvider.ts and the SDK’s SendTransactionOptions. The open question is where a stable key for the same transaction intent should come from; done means retries reuse that key while distinct transfers do not collide. The issue does not name tests, so locate the relevant provider tests before validating the behavior.

Written by the indexing model from the issue text.

Description

Summary

CdpEvmWalletProvider.sendTransaction does not pass an idempotency key, although the CDP SDK it calls accepts one and Coinbase's own docs use idempotency keys elsewhere in this same repository.

// typescript/agentkit/src/wallet-providers/cdpEvmWalletProvider.ts:195-206
async sendTransaction(transaction: TransactionRequest): Promise<Hex> {
  const result = await this.#cdp.evm.sendTransaction({
    address: this.#serverAccount.address,
    transaction: { to, value, data },
    network: this.getCdpSdkNetwork(),
    // no idempotencyKey
  });
  return result.transactionHash;
}

The SDK signature (@coinbase/cdp-sdk, _types/actions/evm/sendTransaction.d.ts) is:

export interface SendTransactionOptions {
  address: Address;
  transaction: Hex | TransactionRequestEIP1559;
  network: SendEvmTransactionBodyNetwork;
  /** The idempotency key. */
  idempotencyKey?: string;
}

So the field exists, is documented, and is not used on the one path that moves value. nativeTransfer (:296) routes through this method, as does every ERC-20 transfer and contract write that reaches this provider. CdpSmartWalletProvider.nativeTransfer (:374) has the same shape.

Why this matters here more than in most SDKs

An agent framework's defining property is that the caller is a model inside a harness that retries. A dropped connection or a timeout after sendTransaction leaves the caller unable to distinguish "the transaction was never submitted" from "it was submitted and the response was lost". With no idempotency key, a retry is a second, independently valid transaction — a second transfer of real value. Nothing in either response marks it as a duplicate, and no replay guard fires, because the second submission genuinely is new.

This is also the case Coinbase already solved. The idempotency-key flow appears in this repo's own examples for wallet creation:

# python/examples/langchain-cdp-chatbot/chatbot.py:51-52
address=config.address,          # Optional, will trigger idempotency flow if not provided
idempotency_key=config.idempotency_key,

Creating a wallet twice is an inconvenience. Sending value twice is not. The protection is applied to the cheaper failure and omitted from the expensive one.

What I checked

  • cdpEvmWalletProvider.ts:195-206 — sendTransaction, no idempotencyKey in the options object.
  • cdpEvmWalletProvider.ts:296-302 — nativeTransfer delegates to it unchanged.
  • cdpSmartWalletProvider.ts:374-380 — same delegation.
  • @coinbase/[email protected] — SendTransactionOptions.idempotencyKey?: string, present and commented as "The idempotency key."
  • A repository-wide search for idempot in TypeScript and Python sources: matches occur only in wallet-creation examples, never in a wallet provider or an action provider.

Limits, stated plainly

This is a code read. I have not run an agent against CDP, induced a timeout mid-transfer and observed two transfers — that experiment is what turns a mechanism into a measured rate, and I would want it before quoting one.

If the CDP backend deduplicates sendTransaction server-side by account and nonce independently of the key, then the omission is harmless and this reduces to a documentation gap — in which case I will publish that correction as prominently as the claim. I could not determine that from outside, and the SDK exposing the parameter suggests the backend does rely on it.

I have also not reviewed the Solana provider's equivalent path in the same detail, so I am not making a claim about it here.

On the fix

The fix is small and local to these providers, and there is a design choice inside it — where a stable key should come from so that a retry of the same intent reuses it while distinct transfers do not collide. That choice is the part that actually matters; the plumbing is trivial. I am not posting the patch.

I would rather explain that than be coy. I have filed seven of these over three weeks, each with the complete remedy and a failing test attached, free. Seven teams shipped fixes, the fastest in 4.3 hours. It built a real public record and it has not been a business, so the finding is free and the fix is the work now.

If it is useful: I read one money path end to end and return every finding tied to your own file and line numbers, each with its patch and a failing test in your own harness. Five working days, written only, no call. $1,200, and no invoice if the path is clean. The deliverable is specified up front so you can check the report against it: https://github.com/aurumflux20/seal/blob/main/docs/REVIEW-DELIVERABLE.md

And if you would rather simply have this one, say so on this thread and I will post it here for nothing. I am not going to withhold a payment-safety fix on a public repository, and I would think less of anyone who did. But it is what I sell, and asking costs you nothing.

Context on the seam: of ten agent-payment money paths read in three days, seven could charge a payer twice on an ambiguous outcome. The public record, with the evidence for each row and nobody named while their finding is open, is at https://aurumflux.co/retry-safety/

Dominant language
TypeScript
Stars
1.3k
Forks
842
PR merge metrics
No merged PRs in 30d

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from coinbase/agentkit

All issues in coinbase/agentkit

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.