From b2285ad622be40eef646b3350b6f267a99c26def Mon Sep 17 00:00:00 2001 From: anzzyspeaksgit Date: Thu, 12 Mar 2026 21:30:45 +0000 Subject: [PATCH 1/3] feat: make `_msgSender` virtual across all base and factory contracts Closes #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. --- contracts/base/ERC20Base.sol | 2 +- contracts/base/ERC20Drop.sol | 2 +- contracts/base/ERC20DropVote.sol | 2 +- contracts/base/ERC20Vote.sol | 2 +- contracts/base/ERC721Base.sol | 2 +- contracts/base/ERC721Drop.sol | 2 +- contracts/base/ERC721LazyMint.sol | 2 +- contracts/base/ERC721Multiwrap.sol | 2 +- .../infra/registry/entrypoint/TWMultichainRegistryRouter.sol | 2 +- contracts/prebuilts/account/dynamic/DynamicAccountFactory.sol | 2 +- contracts/prebuilts/account/managed/ManagedAccountFactory.sol | 2 +- contracts/prebuilts/account/non-upgradeable/AccountFactory.sol | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/contracts/base/ERC20Base.sol b/contracts/base/ERC20Base.sol index 31d05a54d..453b89d4c 100644 --- a/contracts/base/ERC20Base.sol +++ b/contracts/base/ERC20Base.sol @@ -105,7 +105,7 @@ contract ERC20Base is ContractMetadata, Multicall, Ownable, ERC20Permit, IMintab } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC20Drop.sol b/contracts/base/ERC20Drop.sol index 60c61925a..46d9f459c 100644 --- a/contracts/base/ERC20Drop.sol +++ b/contracts/base/ERC20Drop.sol @@ -151,7 +151,7 @@ contract ERC20Drop is ContractMetadata, Multicall, Ownable, ERC20Permit, Primary } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC20DropVote.sol b/contracts/base/ERC20DropVote.sol index 4150ac0e1..b4d7a8ff0 100644 --- a/contracts/base/ERC20DropVote.sol +++ b/contracts/base/ERC20DropVote.sol @@ -129,7 +129,7 @@ contract ERC20DropVote is ContractMetadata, Multicall, Ownable, ERC20Votes, Prim } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC20Vote.sol b/contracts/base/ERC20Vote.sol index 79626a830..179d82212 100644 --- a/contracts/base/ERC20Vote.sol +++ b/contracts/base/ERC20Vote.sol @@ -105,7 +105,7 @@ contract ERC20Vote is ContractMetadata, Multicall, Ownable, ERC20Votes, IMintabl } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC721Base.sol b/contracts/base/ERC721Base.sol index 3d256e3f6..de1f8e7e6 100644 --- a/contracts/base/ERC721Base.sol +++ b/contracts/base/ERC721Base.sol @@ -204,7 +204,7 @@ contract ERC721Base is ERC721AQueryable, ContractMetadata, Multicall, Ownable, R } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC721Drop.sol b/contracts/base/ERC721Drop.sol index 42912647a..b138bc725 100644 --- a/contracts/base/ERC721Drop.sol +++ b/contracts/base/ERC721Drop.sol @@ -306,7 +306,7 @@ contract ERC721Drop is } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC721LazyMint.sol b/contracts/base/ERC721LazyMint.sol index 71929b22d..c60982368 100644 --- a/contracts/base/ERC721LazyMint.sol +++ b/contracts/base/ERC721LazyMint.sol @@ -213,7 +213,7 @@ contract ERC721LazyMint is } /// @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) { return msg.sender; } } diff --git a/contracts/base/ERC721Multiwrap.sol b/contracts/base/ERC721Multiwrap.sol index 6125b059f..dc6ad5e7e 100644 --- a/contracts/base/ERC721Multiwrap.sol +++ b/contracts/base/ERC721Multiwrap.sol @@ -256,7 +256,7 @@ contract ERC721Multiwrap is } /// @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) { return msg.sender; } } diff --git a/contracts/infra/registry/entrypoint/TWMultichainRegistryRouter.sol b/contracts/infra/registry/entrypoint/TWMultichainRegistryRouter.sol index 0075ca570..7107f7859 100644 --- a/contracts/infra/registry/entrypoint/TWMultichainRegistryRouter.sol +++ b/contracts/infra/registry/entrypoint/TWMultichainRegistryRouter.sol @@ -51,7 +51,7 @@ contract TWMultichainRegistryRouter is PermissionsEnumerableLogic, ERC2771Contex return hasRole(DEFAULT_ADMIN_ROLE, _msgSender()); } - function _msgSender() internal view override(ERC2771ContextLogic, PermissionsLogic, Multicall) returns (address) { + function _msgSender() internal view virtual override(ERC2771ContextLogic, PermissionsLogic, Multicall) returns (address) { return ERC2771ContextLogic._msgSender(); } diff --git a/contracts/prebuilts/account/dynamic/DynamicAccountFactory.sol b/contracts/prebuilts/account/dynamic/DynamicAccountFactory.sol index 227a32509..e10b7a379 100644 --- a/contracts/prebuilts/account/dynamic/DynamicAccountFactory.sol +++ b/contracts/prebuilts/account/dynamic/DynamicAccountFactory.sol @@ -55,7 +55,7 @@ contract DynamicAccountFactory is BaseAccountFactory, ContractMetadata, Permissi } /// @notice Returns the sender in the given execution context. - function _msgSender() internal view override(Multicall, Permissions) returns (address) { + function _msgSender() internal view virtual override(Multicall, Permissions) returns (address) { return msg.sender; } } diff --git a/contracts/prebuilts/account/managed/ManagedAccountFactory.sol b/contracts/prebuilts/account/managed/ManagedAccountFactory.sol index c5f51e3ca..8bb2bac00 100644 --- a/contracts/prebuilts/account/managed/ManagedAccountFactory.sol +++ b/contracts/prebuilts/account/managed/ManagedAccountFactory.sol @@ -62,7 +62,7 @@ contract ManagedAccountFactory is BaseAccountFactory, ContractMetadata, Permissi } /// @notice Returns the sender in the given execution context. - function _msgSender() internal view override(Multicall, Permissions) returns (address) { + function _msgSender() internal view virtual override(Multicall, Permissions) returns (address) { return msg.sender; } } diff --git a/contracts/prebuilts/account/non-upgradeable/AccountFactory.sol b/contracts/prebuilts/account/non-upgradeable/AccountFactory.sol index 1ab5ce47c..e398310b7 100644 --- a/contracts/prebuilts/account/non-upgradeable/AccountFactory.sol +++ b/contracts/prebuilts/account/non-upgradeable/AccountFactory.sol @@ -48,7 +48,7 @@ contract AccountFactory is BaseAccountFactory, ContractMetadata, PermissionsEnum } /// @notice Returns the sender in the given execution context. - function _msgSender() internal view override(Multicall, Permissions) returns (address) { + function _msgSender() internal view virtual override(Multicall, Permissions) returns (address) { return msg.sender; } } From 1b2722077e87c5ac5f268c17abca262b5430417d Mon Sep 17 00:00:00 2001 From: anzzyspeaksgit Date: Tue, 17 Mar 2026 17:41:29 +0000 Subject: [PATCH 2/3] fix(ERC20Vote): use _msgSender() consistently in burn and burnFrom --- contracts/base/ERC20Vote.sol | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/base/ERC20Vote.sol b/contracts/base/ERC20Vote.sol index 179d82212..1b63cdb47 100644 --- a/contracts/base/ERC20Vote.sol +++ b/contracts/base/ERC20Vote.sol @@ -61,7 +61,7 @@ contract ERC20Vote is ContractMetadata, Multicall, Ownable, ERC20Votes, IMintabl */ function burn(uint256 _amount) external virtual { require(balanceOf(_msgSender()) >= _amount, "not enough balance"); - _burn(msg.sender, _amount); + _burn(_msgSender(), _amount); } /** @@ -74,9 +74,9 @@ contract ERC20Vote is ContractMetadata, Multicall, Ownable, ERC20Votes, IMintabl function burnFrom(address _account, uint256 _amount) external virtual override { require(_canBurn(), "Not authorized to burn."); require(balanceOf(_account) >= _amount, "not enough balance"); - uint256 decreasedAllowance = allowance(_account, msg.sender) - _amount; - _approve(_account, msg.sender, 0); - _approve(_account, msg.sender, decreasedAllowance); + uint256 decreasedAllowance = allowance(_account, _msgSender()) - _amount; + _approve(_account, _msgSender(), 0); + _approve(_account, _msgSender(), decreasedAllowance); _burn(_account, _amount); } @@ -86,26 +86,26 @@ contract ERC20Vote is ContractMetadata, Multicall, Ownable, ERC20Votes, IMintabl /// @dev Returns whether contract metadata can be set in the given execution context. function _canSetContractURI() internal view virtual override returns (bool) { - return msg.sender == owner(); + return _msgSender() == owner(); } /// @dev Returns whether tokens can be minted in the given execution context. function _canMint() internal view virtual returns (bool) { - return msg.sender == owner(); + return _msgSender() == owner(); } /// @dev Returns whether tokens can be burned in the given execution context. function _canBurn() internal view virtual returns (bool) { - return msg.sender == owner(); + return _msgSender() == owner(); } /// @dev Returns whether owner can be set in the given execution context. function _canSetOwner() internal view virtual override returns (bool) { - return msg.sender == owner(); + return _msgSender() == owner(); } /// @notice Returns the sender in the given execution context. function _msgSender() internal view virtual override(Multicall, Context) returns (address) { - return msg.sender; + return _msgSender(); } } From c767c0673587bca144f9f83c5c39f1b53cf9957b Mon Sep 17 00:00:00 2001 From: anzzyspeaksgit Date: Tue, 17 Mar 2026 20:01:55 +0000 Subject: [PATCH 3/3] fix(ERC20Vote): resolve _msgSender infinite recursion by calling super --- contracts/base/ERC20Vote.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/base/ERC20Vote.sol b/contracts/base/ERC20Vote.sol index 1b63cdb47..a93cbb50b 100644 --- a/contracts/base/ERC20Vote.sol +++ b/contracts/base/ERC20Vote.sol @@ -106,6 +106,6 @@ contract ERC20Vote is ContractMetadata, Multicall, Ownable, ERC20Votes, IMintabl /// @notice Returns the sender in the given execution context. function _msgSender() internal view virtual override(Multicall, Context) returns (address) { - return _msgSender(); + return super._msgSender(); } }