feat: added functionality for transaction cancel#134
Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a new cancelTransaction utility and tests, documentation, and exports. The utility sends a 0-value replacement transaction to self using the same nonce and an inflated gas price (doubles gasPrice when derived from a fetched tx); supports ethers v5/v6 signers and requires either transactionHash or explicit nonce+gasPrice. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Signer
participant Provider
participant Blockchain
rect rgba(100, 150, 200, 0.5)
note over User,Blockchain: Mode 1 — Cancel by Transaction Hash
User->>Signer: cancelTransaction(signer, { transactionHash })
Signer->>Provider: getTransaction(transactionHash)
Provider-->>Signer: originalTx (nonce, gasPrice?)
alt gasPrice present
Signer->>Signer: gasPrice := originalTx.gasPrice * 2
Signer->>Signer: build tx(to=self, value=0, nonce, gasPrice, gasLimit=21000)
Signer->>Blockchain: sendTransaction(replacement)
Blockchain-->>Signer: replacementHash
Signer-->>User: return replacementHash
else gasPrice missing
Signer-->>User: throw (EIP-1559 tx has no gasPrice)
end
end
rect rgba(150, 100, 200, 0.5)
note over User,Blockchain: Mode 2 — Cancel by Explicit Parameters
User->>Signer: cancelTransaction(signer, { nonce, gasPrice })
Signer->>Signer: build tx(to=self, value=0, nonce, gasPrice, gasLimit=21000)
Signer->>Blockchain: sendTransaction(replacement)
Blockchain-->>Signer: replacementHash
Signer-->>User: return replacementHash
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/__tests__/transaction/cancel.test.ts (1)
22-84: Add coverage for the untested v5 and EIP-1559 branches.Current tests are good, but two public behaviors remain unguarded: the v5 sendTransaction branch and the EIP-1559
gasPrice == nullerror path.🧪 Suggested additional tests
+ it('throws when transactionHash resolves to EIP-1559 tx (no gasPrice)', async () => { + const getTransaction = vi.fn().mockResolvedValue({ nonce: 7, gasPrice: null }); + const signer = { + getAddress: vi.fn().mockResolvedValue(mockAddress), + provider: { _isProvider: false, provider: {}, getTransaction }, + sendTransaction: vi.fn(), + } as any; + + await expect( + cancelTransaction(signer, { transactionHash: '0xabc' }), + ).rejects.toThrow(/EIP-1559/); + }); + + it('sends replacement tx through v5-style signer path', async () => { + const mockHash = '0xv5hash'; + const sendTransaction = vi.fn().mockResolvedValue({ hash: mockHash }); + const signer = { + getAddress: vi.fn().mockResolvedValue(mockAddress), + provider: { _isProvider: true }, + sendTransaction, + } as any; + + const hash = await cancelTransaction(signer, { nonce: '3', gasPrice: '1000000000' }); + expect(hash).toBe(mockHash); + expect(sendTransaction).toHaveBeenCalledTimes(1); + });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/__tests__/transaction/cancel.test.ts` around lines 22 - 84, Tests are missing coverage for the v5 sendTransaction branch and the EIP‑1559 path where gasPrice === null; add unit tests that exercise cancelTransaction for those cases. Specifically, add a test that constructs a v5-style signer (provider._isProvider === true or provider.provider present as in your code's v5 detection) with sendTransaction mocked to resolve and assert the replacement tx fields are built as expected using numeric gasPrice and nonce; and add a test that simulates an EIP‑1559 pending tx by having provider.getTransaction return an object with gasPrice === null (or undefined) to verify cancelTransaction throws the expected error path for EIP‑1559; reference the cancelTransaction function and the branches that check provider._isProvider / provider.provider and the gasPrice === null check to locate where to hook the mocks.README.md (1)
1142-1145: Tighten repetitive throw bullets for readability.The four bullets start with “If…”, which makes this section a bit harder to scan quickly.
✍️ Suggested wording tweak
-- If the signer has no provider. -- If neither `(nonce, gasPrice)` nor `transactionHash` is provided. -- If `transactionHash` is given but the transaction is not found. -- If the transaction uses EIP-1559 (no `gasPrice`); in that case use nonce and gas price explicitly. +- Signer has no provider. +- Neither `(nonce, gasPrice)` nor `transactionHash` is provided. +- The provided `transactionHash` is not found. +- The transaction is EIP-1559 (no `gasPrice`); in that case use explicit nonce and gas price.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 1142 - 1145, The four README bullets are repetitive starting each with "If..."; revise them to be short, parallel phrases that preserve the original conditions but improve scannability — e.g. "Signer has no provider.", "Neither (nonce, gasPrice) nor transactionHash provided.", "transactionHash provided but transaction not found.", "Transaction uses EIP-1559 (no gasPrice); use explicit nonce and gasPrice in that case." — update the lines replacing the existing bullets so they remain accurate but read more concisely and consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/transaction/cancel.ts`:
- Around line 73-94: Remove the brittle provider-version branching that calls
isV6EthersProvider(signer.provider); instead always call signer.sendTransaction
with a single unified transaction object using BigNumberish-compatible fields so
both ethers v5 and v6 signers work: use nonce as a numeric/string value parsed
from transactionNonce (e.g., parseInt(transactionNonce,10) or keep as string if
acceptable), set gasPrice to a BigNumberish (e.g., transactionGasPrice as string
or BigNumber) and gasLimit to a numeric/BigNumberish (21000 or "21000"), and
remove references to SignerV6/SignerV5 and signer.provider—update the calls
around sendTransaction, transactionNonce, transactionGasPrice, and address to
use these unified types.
---
Nitpick comments:
In `@README.md`:
- Around line 1142-1145: The four README bullets are repetitive starting each
with "If..."; revise them to be short, parallel phrases that preserve the
original conditions but improve scannability — e.g. "Signer has no provider.",
"Neither (nonce, gasPrice) nor transactionHash provided.", "transactionHash
provided but transaction not found.", "Transaction uses EIP-1559 (no gasPrice);
use explicit nonce and gasPrice in that case." — update the lines replacing the
existing bullets so they remain accurate but read more concisely and
consistently.
In `@src/__tests__/transaction/cancel.test.ts`:
- Around line 22-84: Tests are missing coverage for the v5 sendTransaction
branch and the EIP‑1559 path where gasPrice === null; add unit tests that
exercise cancelTransaction for those cases. Specifically, add a test that
constructs a v5-style signer (provider._isProvider === true or provider.provider
present as in your code's v5 detection) with sendTransaction mocked to resolve
and assert the replacement tx fields are built as expected using numeric
gasPrice and nonce; and add a test that simulates an EIP‑1559 pending tx by
having provider.getTransaction return an object with gasPrice === null (or
undefined) to verify cancelTransaction throws the expected error path for
EIP‑1559; reference the cancelTransaction function and the branches that check
provider._isProvider / provider.provider and the gasPrice === null check to
locate where to hook the mocks.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
README.mdsrc/__tests__/transaction/cancel.test.tssrc/index.tssrc/transaction/cancel.tssrc/transaction/index.ts
|
Caution Docstrings generation - FAILED No docstrings were generated. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/transaction/cancel.ts (1)
13-20: Consider makinggasLimitconfigurable.Line 84 hardcodes
21000, which is fine for EOAs but can fail for contract-wallet self-transfers. A configurable option improves compatibility without changing defaults.Suggested refactor
export interface CancelTransactionOptions { /** Pending transaction nonce (use with gasPrice, or use transactionHash instead) */ nonce?: string; /** Gas price higher than the pending transaction (use with nonce) */ gasPrice?: string; + /** Gas limit for replacement transaction (default: 21000) */ + gasLimit?: string; /** Pending transaction hash; nonce and gas price will be fetched and gas price increased by 100% */ transactionHash?: string; } @@ - const { nonce, gasPrice, transactionHash } = options; + const { nonce, gasPrice, transactionHash, gasLimit = '21000' } = options; @@ - gasLimit: 21000, + gasLimit,Also applies to: 84-84
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/transaction/cancel.ts` around lines 13 - 20, The CancelTransactionOptions interface and cancellation logic currently hardcode gasLimit to 21000, which fails for contract-wallet self-transfers; add an optional gasLimit?: string | number to CancelTransactionOptions and update the cancel transaction flow (the function that builds the replacement tx where gasLimit is set to 21000) to use options.gasLimit when provided, otherwise default to 21000; ensure the code converts/validates the provided gasLimit into the same numeric type used when constructing the transaction (and preserve existing behavior if undefined).README.md (1)
1142-1145: Polish repeated “If …” starts in throws list.These consecutive bullets read more cleanly if rewritten as noun-style conditions.
Suggested wording tweak
-- If the signer has no provider. -- If neither `(nonce, gasPrice)` nor `transactionHash` is provided. -- If `transactionHash` is given but the transaction is not found. -- If the transaction uses EIP-1559 (no `gasPrice`); in that case use nonce and gas price explicitly. +- Signer has no provider. +- Neither `(nonce, gasPrice)` nor `transactionHash` is provided. +- `transactionHash` is provided but the transaction is not found. +- Transaction uses EIP-1559 (no `gasPrice`); in that case use nonce and gas price explicitly.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@README.md` around lines 1142 - 1145, The bullet list in the README throws section uses repetitive sentence-starts ("If ...")—rewrite the consecutive bullets into noun-style conditions for conciseness and parallelism (e.g., "Missing provider for signer", "Neither (nonce, gasPrice) nor transactionHash provided", "Provided transactionHash not found", "EIP-1559 transaction (no gasPrice) — require explicit nonce and gas price"). Update the bullets in the throws list so each item begins with a short noun phrase or condition and preserves the original meanings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/transaction/cancel.ts`:
- Around line 50-51: The code calls the potentially-undefined method
signer.provider.getTransaction! when transactionHash is present; instead guard
the optional method before invoking it (e.g., check if
signer.provider.getTransaction is a function or use optional chaining) and
follow a controlled error path if it's missing—update the block using
transactionHash to call signer.provider.getTransaction only after verifying its
existence and throw or return a clear, handled error (or fallback behavior) so
runtime errors are avoided.
- Around line 77-84: Validate the nonce and gas price strictly before calling
signer.sendTransaction: ensure transactionNonce is a pure decimal integer string
(e.g., /^\d+$/) and convert to a number only after that check (assign to
nonceNum), and ensure transactionGasPrice is a valid positive numeric/BigNumber
value; if either check fails, throw/return an error instead of proceeding to
signer.sendTransaction so you never pass a parsed, permissive value like "7abc"
into the nonce or an invalid gas price into the gasPrice field.
---
Nitpick comments:
In `@README.md`:
- Around line 1142-1145: The bullet list in the README throws section uses
repetitive sentence-starts ("If ...")—rewrite the consecutive bullets into
noun-style conditions for conciseness and parallelism (e.g., "Missing provider
for signer", "Neither (nonce, gasPrice) nor transactionHash provided", "Provided
transactionHash not found", "EIP-1559 transaction (no gasPrice) — require
explicit nonce and gas price"). Update the bullets in the throws list so each
item begins with a short noun phrase or condition and preserves the original
meanings.
In `@src/transaction/cancel.ts`:
- Around line 13-20: The CancelTransactionOptions interface and cancellation
logic currently hardcode gasLimit to 21000, which fails for contract-wallet
self-transfers; add an optional gasLimit?: string | number to
CancelTransactionOptions and update the cancel transaction flow (the function
that builds the replacement tx where gasLimit is set to 21000) to use
options.gasLimit when provided, otherwise default to 21000; ensure the code
converts/validates the provided gasLimit into the same numeric type used when
constructing the transaction (and preserve existing behavior if undefined).
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
README.mdsrc/__tests__/transaction/cancel.test.tssrc/index.tssrc/transaction/cancel.tssrc/transaction/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- src/transaction/index.ts
- src/tests/transaction/cancel.test.ts
- src/index.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
## [2.11.0](v2.10.0...v2.11.0) (2026-03-03) ### Features * added functionality for transaction cancel ([#134](#134)) ([a6e973e](a6e973e))
|
🎉 This PR is included in version 2.11.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |



Summary
What is the background of this pull request?
Changes
Issues
What are the related issues or stories?
Summary by CodeRabbit
New Features
Documentation
Tests