-
Notifications
You must be signed in to change notification settings - Fork 679
[SDK] Fix: EIP1193.toProvider() removeListener is now functional #8886
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
0xFirekeeper
merged 3 commits into
thirdweb-dev:main
from
blockgroot:sdk/eip1193-remove-listener-noop
Aug 13, 2026
+71
−3
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "thirdweb": patch | ||
| --- | ||
|
|
||
| Fix: `EIP1193.toProvider()`'s `removeListener` is no longer a no-op. Previously, `removeListener` discarded the unsubscribe function returned by `wallet.subscribe()`, so listeners registered via `provider.on(...)` (e.g. `accountsChanged`, `chainChanged`, `disconnect`) could never actually be detached — they kept firing after callers (such as wagmi connectors) believed they had unsubscribed. `removeListener` now tracks and invokes the correct unsubscribe function per `(event, listener)` pair. |
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: thirdweb-dev/js
Length of output: 20867
🏁 Script executed:
Repository: thirdweb-dev/js
Length of output: 17223
🌐 Web query:
EIP-1193 Provider event emitter on removeListener duplicate listener registrations semantics💡 Result:
EIP-1193 mandates that providers implement event handling methods, specifically
onandremoveListener, following the Node.jsEventEmitterAPI [1][2]. Under this standard, the semantics for duplicate listener registrations and their removal are governed by the underlying Node.jsEventEmitterbehavior [1][2][3][4]. Regarding duplicate listener registrations and removal: 1. Duplicate Registrations: Callingonmultiple times with the same listener function for the same event name results in that listener being added to the event's internal listener array multiple times [3][4]. Each registration is independent; no checks are performed to prevent duplicates [3][4]. 2. Removal Semantics: TheremoveListenermethod removes at most one instance of a listener from the listener array [3][4]. If a listener was added multiple times,removeListenermust be called an equal number of times to remove all registered instances [3][4]. 3. Removal Order: When a function has been added multiple times,removeListenertypically removes the most recently added instance [3][4]. While EIP-2700, which builds upon these concepts, allows providers the flexibility to either support multiple callbacks or de-duplicate them [5][6], EIP-1193 explicitly ties its implementation requirements to the standard Node.jsEventEmitterAPI [1][2], which enforces the behavior described above. Therefore, developers should assume that they must manage the lifecycle of every registered listener instance individually.Citations:
🏁 Script executed:
Repository: thirdweb-dev/js
Length of output: 17223
🏁 Script executed:
Repository: thirdweb-dev/js
Length of output: 50373
🌐 Web query:
site:eips.ethereum.org/EIPS/eip-1193 "EventEmitter" "removeListener"💡 Result:
The removeListener method is a core part of the Node.js EventEmitter API used to unsubscribe a specific listener function from an event [1]. When called, removeListener removes the specified listener from the listener array for the event named eventName [1]. Key behaviors of removeListener include: 1. Unsubscribing: It requires the original reference to the listener function that was used to subscribe to the event [1]. If the function was wrapped or created anonymously during subscription, it cannot be removed using this method. 2. Alias: In the Node.js EventEmitter API, the off method is an alias for removeListener, meaning they function identically and can be used interchangeably to remove event listeners. 3. Behavior: removeListener will remove at most one instance of a listener from the listener array. If any single listener has been added multiple times for the same eventName, removeListener must be called multiple times to remove each instance. Example usage: const logAccounts = (accounts) => { console.log(accounts); }; // Subscribe to the event emitter.on('accountsChanged', logAccounts); // Unsubscribe from the event emitter.removeListener('accountsChanged', logAccounts); By convention, other APIs that implement the Node.js EventEmitter interface, such as the Ethereum Provider API, also support removeListener to manage event subscriptions [1].
Citations:
🌐 Web query:
site:nodejs.org/api/events.html removeListener multiple instances listener added multiple times💡 Result:
In Node.js, the EventEmitter.removeListener method removes only one instance of a listener at a time [1]. If a specific listener function has been added to an event multiple times, calling removeListener once will remove only the most recently added instance [1]. To completely remove all instances of a listener that was added multiple times, you must call removeListener repeatedly for each instance until all are removed [1]. This behavior occurs because EventEmitter does not check if a listener has already been added when you use on or prependListener [1]. Consequently, every call to these methods appends a new instance to the internal listener array, all of which will be triggered when the event is emitted [1].
Citations:
🏁 Script executed:
Repository: thirdweb-dev/js
Length of output: 15185
🏁 Script executed:
Repository: thirdweb-dev/js
Length of output: 3380
Preserve duplicate listener registrations end to end.
listeners.set(listener, unsubscribe)overwrites earlier registrations. Store one unsubscribe callback per registration and remove one perremoveListenercall. BecausecreateWalletEmitteruses aSet, also test duplicate delivery with an independent-registrationwallet.subscribestub or update the emitter implementation.🤖 Prompt for AI Agents