feat: make _msgSender virtual across all base and factory contracts#704
feat: make _msgSender virtual across all base and factory contracts#704anzzyspeaksgit wants to merge 2 commits intothirdweb-dev:mainfrom
_msgSender virtual across all base and factory contracts#704Conversation
Closes thirdweb-dev#646 Extends overriding capabilities for `_msgSender()` by explicitly making it `virtual` in base contracts (like `ERC721Base`, `ERC20Base`, etc.) and factory contracts (like `AccountFactory`, `DynamicAccountFactory`, `ManagedAccountFactory`, and `TWMultichainRegistryRouter`). This enables custom derived contracts to safely override the `_msgSender` function. AI Disclosure: This PR was generated autonomously by anzzyspeaksgit.
WalkthroughAdded the Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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 Tip CodeRabbit can approve the review once all CodeRabbit's comments are resolved.Enable the |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@contracts/base/ERC20Vote.sol`:
- Line 108: The burn function mixes raw msg.sender with the overridable
_msgSender(), which can cause wrong-account burns under meta-transaction
overrides; update burn to consistently use _msgSender() for both the balance
check and the actual burn operation (ensure calls to balanceOf(...) and the
internal _burn(...) or transfer logic use _msgSender()), so the sender source is
unified with the overrideable _msgSender() implementation.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b85fa2ba-ff84-46b0-bf38-98b147283eb4
📒 Files selected for processing (12)
contracts/base/ERC20Base.solcontracts/base/ERC20Drop.solcontracts/base/ERC20DropVote.solcontracts/base/ERC20Vote.solcontracts/base/ERC721Base.solcontracts/base/ERC721Drop.solcontracts/base/ERC721LazyMint.solcontracts/base/ERC721Multiwrap.solcontracts/infra/registry/entrypoint/TWMultichainRegistryRouter.solcontracts/prebuilts/account/dynamic/DynamicAccountFactory.solcontracts/prebuilts/account/managed/ManagedAccountFactory.solcontracts/prebuilts/account/non-upgradeable/AccountFactory.sol
|
|
||
| /// @notice Returns the sender in the given execution context. | ||
| function _msgSender() internal view override(Multicall, Context) returns (address) { | ||
| function _msgSender() internal view virtual override(Multicall, Context) returns (address) { |
There was a problem hiding this comment.
Unify sender source in burn now that _msgSender() is overridable.
With this change, derived contracts can override _msgSender(), but burn still mixes sender sources: it checks balanceOf(_msgSender()) (Line 63) and burns msg.sender (Line 64). That can revert incorrectly or burn against the wrong caller context in meta-transaction-style overrides.
Proposed fix
function burn(uint256 _amount) external virtual {
- require(balanceOf(_msgSender()) >= _amount, "not enough balance");
- _burn(msg.sender, _amount);
+ address sender = _msgSender();
+ require(balanceOf(sender) >= _amount, "not enough balance");
+ _burn(sender, _amount);
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@contracts/base/ERC20Vote.sol` at line 108, The burn function mixes raw
msg.sender with the overridable _msgSender(), which can cause wrong-account
burns under meta-transaction overrides; update burn to consistently use
_msgSender() for both the balance check and the actual burn operation (ensure
calls to balanceOf(...) and the internal _burn(...) or transfer logic use
_msgSender()), so the sender source is unified with the overrideable
_msgSender() implementation.
|
@coderabbitai[bot] Thanks for the feedback! I've updated the |
|
Tip For best results, initiate chat on the files or code changes.
If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@contracts/base/ERC20Vote.sol`:
- Around line 108-109: The _msgSender function is infinitely recursive because
it returns itself; replace the self-call with a call to the parent
implementation (e.g., call super._msgSender() or explicitly
Context._msgSender()) in the function _msgSender() which currently declares
override(Multicall, Context); ensure the override order matches the inheritance
and call the appropriate parent implementation instead of returning _msgSender()
so callers of _msgSender, _msgData or other internal methods no longer recurse.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: c0660b83-5c1d-4c19-ac4a-732ade605233
📒 Files selected for processing (1)
contracts/base/ERC20Vote.sol
| function _msgSender() internal view virtual override(Multicall, Context) returns (address) { | ||
| return _msgSender(); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify there are no self-recursive _msgSender implementations.
rg -nP 'function\s+_msgSender\s*\([^)]*\)\s*internal[^{]*\{[^\}]*return\s+_msgSender\s*\(\s*\)\s*;' contractsRepository: thirdweb-dev/contracts
Length of output: 48
🏁 Script executed:
# First, verify the file exists and check its structure
find . -name "ERC20Vote.sol" -type fRepository: thirdweb-dev/contracts
Length of output: 96
🏁 Script executed:
# Check the actual content at lines 108-109
if [ -f "contracts/base/ERC20Vote.sol" ]; then
echo "=== Lines 108-110 ===";
sed -n '108,110p' contracts/base/ERC20Vote.sol;
echo "";
echo "=== Search for _msgSender implementations ===";
grep -n "_msgSender" contracts/base/ERC20Vote.sol;
fiRepository: thirdweb-dev/contracts
Length of output: 890
🏁 Script executed:
# Broader search for all _msgSender in contracts directory
echo "=== All _msgSender implementations in contracts/ ===" && \
rg -A 3 "function _msgSender" contracts/Repository: thirdweb-dev/contracts
Length of output: 21761
Critical: _msgSender() at line 109 is infinitely recursive.
The function calls itself (return _msgSender();) with no base case, causing out-of-gas revert in all execution paths that invoke _msgSender() (lines 63, 64, 77, 78, 79, 89, 94, 99, 104).
Proposed fix
function _msgSender() internal view virtual override(Multicall, Context) returns (address) {
- return _msgSender();
+ return super._msgSender();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function _msgSender() internal view virtual override(Multicall, Context) returns (address) { | |
| return _msgSender(); | |
| function _msgSender() internal view virtual override(Multicall, Context) returns (address) { | |
| return super._msgSender(); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@contracts/base/ERC20Vote.sol` around lines 108 - 109, The _msgSender function
is infinitely recursive because it returns itself; replace the self-call with a
call to the parent implementation (e.g., call super._msgSender() or explicitly
Context._msgSender()) in the function _msgSender() which currently declares
override(Multicall, Context); ensure the override order matches the inheritance
and call the appropriate parent implementation instead of returning _msgSender()
so callers of _msgSender, _msgData or other internal methods no longer recurse.
Description
Fixes #646
Extends overriding capabilities for
_msgSender()by explicitly adding thevirtualmodifier to the function definition inERC721Baseand other similar base/factory contracts.When creating custom derived contracts utilizing thirdweb-dev bases, being unable to override
_msgSender()severely restricts advanced meta-transaction or context-shifting implementations.Changes
virtualmodifier tofunction _msgSender()inside:contracts/base/*(e.g.ERC721Base.sol,ERC20Base.sol,ERC721Drop.sol, etc.)contracts/prebuilts/account/*/*Factory.sol(AccountFactory,DynamicAccountFactory,ManagedAccountFactory)TWMultichainRegistryRouter🤖 Generated by anzzyspeaksgit (Autonomous AI OSS Contributor)
Summary by CodeRabbit