Repository navigation
Conversation
🟡 Heimdall Review Status
|
CdpEvmWalletProvider.sendTransaction and CdpSmartWalletProvider.sendTransaction call the CDP SDK without an idempotency key, although SendTransactionOptions and SendUserOperationOptions both declare one. nativeTransfer delegates into those methods on both providers, so every value-moving path reaches the SDK with no key. An agent harness retries after an ambiguous outcome. With no key, a retry after a lost response is a second, independently valid transfer of the same value and no replay guard fires, because the second submission genuinely is new. Forward an optional caller-supplied key on both TypeScript providers and on the Python CdpEvmWalletProvider send/native-transfer paths. The key is not generated inside the provider: a key minted per call would differ on the retry and deduplicate nothing. It is a property of the caller's logical intent, so callers pass it and the default keeps existing behaviour unchanged.
Baophan00
force-pushed
the
fix/cdp-idempotency-key
branch
from
October 1, 2026 12:10
00089ce to
6398915
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CdpEvmWalletProvider.sendTransactionandCdpSmartWalletProvider.sendTransactioncall the CDP SDK without an idempotency key, althoughSendTransactionOptionsandSendUserOperationOptionsboth declare one.nativeTransferdelegates into those methods on both providers, so every value-moving path on the CDP providers reaches the SDK with no key.An agent harness retries after an ambiguous outcome. With no key, a retry after a lost response is a second, independently valid transfer of the same value, and no replay guard fires because the second submission genuinely is new.
This forwards an optional caller-supplied key on both TypeScript providers and on the Python
CdpEvmWalletProvidersend / native-transfer paths.Closes #1483.
Why the key is a parameter and not generated inside the provider
This is the part that decides whether the change does anything. A key minted inside
sendTransactionis a new key on every call, including a retry — so it deduplicates nothing. The key has to be a property of the caller's logical intent: same intent, same key; new transfer, new key. Only the caller knows which of those it is holding, so the key is a parameter and the provider's default leaves it unset, which keeps existing behaviour byte-identical.Files changed
typescript/agentkit/src/wallet-providers/cdpEvmWalletProvider.ts—sendTransactionandnativeTransferaccept an optionalidempotencyKeyand forward it tocdp.evm.sendTransaction.typescript/agentkit/src/wallet-providers/cdpSmartWalletProvider.ts— same, forwarding tocdp.evm.sendUserOperation.python/coinbase-agentkit/coinbase_agentkit/wallet_providers/cdp_evm_wallet_provider.py—send_transactionandnative_transferaccept an optionalidempotency_key.changelog.dentry.Test plan
TypeScript (
typescript/agentkit):node node_modules/jest/bin/jest.js --no-cache --testMatch='**/*.test.ts'— 908 passed, 62 suites.tsc --noEmit— clean.Python (
python/coinbase-agentkit):uv run pytest -m "not (e2e or integration)"— 673 passed, 35 deselected.ruff checkandruff format --check— clean.The new tests were confirmed to fail on the unmodified code and pass with it, so they actually pin the behaviour rather than passing vacuously. Reverting the provider changes only:
cdpEvmWalletProvider.test.tscdpSmartWalletProvider.test.tstest_transactions.py(CDP EVM server wallet)Limits, stated plainly
This is a code read plus unit tests against the mocked SDK. I have not induced a real timeout mid-transfer against CDP and counted two landing transfers — that would establish CDP's server-side dedup behaviour, which I cannot determine from outside. What this PR fixes is the local omission: the parameter the SDK exposes is now reachable from the provider that moves the value. If the CDP backend already deduplicates by account and nonce independently of the key, then this is a documentation-level gap and the tests here still describe the intended contract.