Skip to content

feat: added functionality for transaction cancel#134

Merged
RishabhS7 merged 4 commits intomainfrom
TT-1214/transaction-cancel
Mar 3, 2026
Merged

feat: added functionality for transaction cancel#134
RishabhS7 merged 4 commits intomainfrom
TT-1214/transaction-cancel

Conversation

@manishdex25
Copy link
Copy Markdown
Contributor

@manishdex25 manishdex25 commented Mar 2, 2026

Summary

What is the background of this pull request?

Changes

  • What are the changes made in this pull request?
  • Change this and that, etc...

Issues

What are the related issues or stories?

Summary by CodeRabbit

  • New Features

    • Added a transaction cancellation utility to replace pending Ethereum transactions with a 0-value self-send using the same nonce and higher gas price (supports ethers v5/v6); returns the replacement transaction hash.
  • Documentation

    • Added a “Transaction Cancel” section with examples for canceling by transaction hash or by explicit nonce/gasPrice.
  • Tests

    • Added unit tests covering success paths and error cases (missing provider/inputs, missing transaction).

@manishdex25 manishdex25 requested a review from RishabhS7 March 2, 2026 18:23
@manishdex25 manishdex25 self-assigned this Mar 2, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 2, 2026

Warning

Rate limit exceeded

@manishdex25 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 34 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 9d817a8 and 0b7197c.

📒 Files selected for processing (1)
  • src/transaction/cancel.ts
📝 Walkthrough

Walkthrough

Adds 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

Cohort / File(s) Summary
Core Implementation & Exports
src/transaction/cancel.ts, src/transaction/index.ts, src/index.ts
New cancelTransaction with CancelTransactionOptions and CancelTransactionSigner. Validates signer/provider, supports two modes: (a) transactionHash — fetches original tx, uses its nonce and doubles gasPrice (errors if gasPrice unavailable such as EIP-1559 cases), (b) explicit nonce + gasPrice — constructs 0-value self-transfer with gasLimit: 21000. Re-exports types and function at transaction and top-level API.
Tests
src/__tests__/transaction/cancel.test.ts
Adds tests covering: missing provider error, missing parameters error, explicit nonce+gasPrice flow (v6-style signer), transactionHash flow (fetch + gasPrice doubling + error when tx not found), and removal of prior helper tests.
Documentation
README.md
Adds "10. Transaction Cancel" TOC entry and a detailed section describing the cancelTransaction utility, usage examples for both modes, return value (Promise replacement hash), and error cases (missing provider/params/transaction, EIP-1559 without gasPrice).

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I hop and nudge a pending fee away,
A zero-value hop to save the day,
Double the gas when the old hash we find,
Or use your nonce and gas if you’ve defined,
Quietly replaced — a tidy blockchain play.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description only contains placeholder template sections without substantive content—no background, specific changes, or related issues are documented. Fill in the Summary section with background context, detail specific changes (e.g., new cancelTransaction function, test coverage, README documentation), and reference related issues or stories.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: added functionality for transaction cancel' accurately describes the main change: adding a new cancelTransaction feature to handle pending Ethereum transaction cancellation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch TT-1214/transaction-cancel

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 == null error 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

📥 Commits

Reviewing files that changed from the base of the PR and between 612480a and c40ac90.

📒 Files selected for processing (5)
  • README.md
  • src/__tests__/transaction/cancel.test.ts
  • src/index.ts
  • src/transaction/cancel.ts
  • src/transaction/index.ts

Comment thread src/transaction/cancel.ts Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 3, 2026

Caution

Docstrings generation - FAILED

No docstrings were generated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/transaction/cancel.ts (1)

13-20: Consider making gasLimit configurable.

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

📥 Commits

Reviewing files that changed from the base of the PR and between c40ac90 and 9d817a8.

📒 Files selected for processing (5)
  • README.md
  • src/__tests__/transaction/cancel.test.ts
  • src/index.ts
  • src/transaction/cancel.ts
  • src/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

Comment thread src/transaction/cancel.ts Outdated
Comment thread src/transaction/cancel.ts Outdated
manishdex25 and others added 2 commits March 3, 2026 10:46
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Mar 3, 2026

@RishabhS7 RishabhS7 merged commit a6e973e into main Mar 3, 2026
13 checks passed
@RishabhS7 RishabhS7 deleted the TT-1214/transaction-cancel branch March 3, 2026 06:08
nghaninn pushed a commit that referenced this pull request Mar 3, 2026
## [2.11.0](v2.10.0...v2.11.0) (2026-03-03)

### Features

* added functionality for transaction cancel ([#134](#134)) ([a6e973e](a6e973e))
@tradetrustimda
Copy link
Copy Markdown

🎉 This PR is included in version 2.11.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants