Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Missing _msgSender() in NativeMetaTransaction Breaks Meta-Transaction Functionality and Role-Based Access Control

Summary

The NativeMetaTransaction contract is missing the critical _msgSender() function, which is essential for meta-transaction functionality. Without this implementation, the contract cannot properly handle meta-transactions despite having the execution logic in place. This means the entire meta-transaction feature will not work as intended, as there's no way to properly recover the original sender's address during the execution of functions.

The NativeMetaTransaction contract implements the meta-transaction execution logic including signature verification and nonce management, but omits the crucial _msgSender() function. The contract's executeMetaTransaction function appends the user's address to the function call data:

https://github.com/Cyfrin/2024-11-one-world/blob/main/contracts/meta-transaction/NativeMetaTransaction.sol#L33

(bool success, bytes memory returnData) = address(this).call{value: msg.value}(
abi.encodePacked(functionSignature, userAddress)
);

However, without a corresponding _msgSender() implementation in NativeMetaTransaction, there's no way to extract this appended address during the actual function execution. This missing piece breaks the connection between meta-transaction execution and sender recovery.

Scenario

The absence of _msgSender() in NativeMetaTransaction breaks the meta-transaction functionality. Consider this real-world scenario:

// User Alice wants to mint tokens but has no ETH for gas
// She creates and signs a meta-transaction
bytes memory mintData = abi.encodeWithSignature(
"mint(address,uint256,uint256,bytes)",
aliceAddress,
tokenId,
1,
"0x"
);
// Relayer executes the meta-transaction
contract.executeMetaTransaction(
aliceAddress, // Alice's address
mintData, // Mint function call
sigR, sigS, sigV // Alice's signature
);
// Inside executeMetaTransaction:
// 1. Signature is verified ✓
// 2. Function call is made with Alice's address appended ✓
// 3. mint() is called
// 4. mint() checks MINTER_ROLE...
// Problem: Without _msgSender() in NativeMetaTransaction
// The role check fails because it can't recover Alice's address
// Even if Alice has MINTER_ROLE, the transaction reverts

The root cause is simple but severe - when executeMetaTransaction appends the user's address:

(bool success, bytes memory returnData) = address(this).call{value: msg.value}(
abi.encodePacked(functionSignature, userAddress)
);

There's no corresponding _msgSender() implementation to extract this address. This means:

  1. Meta-transactions will fail for all role-protected functions

  2. Users can't use gasless transactions even with valid permissions

  3. The entire meta-transaction infrastructure becomes non-functional

Recommended Fix

Add to NativeMetaTransaction:

function _msgSender() internal view virtual returns (address sender) {
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
sender := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
return sender;
}
return msg.sender;
}

After fix, the scenario works:

// Same meta-transaction from Alice
contract.executeMetaTransaction(
aliceAddress,
mintData,
sigR, sigS, sigV
);
// Now:
// 1. Signature verification ✓
// 2. Function call with appended address ✓
// 3. mint() called
// 4. _msgSender() correctly returns Alice's address ✓
// 5. MINTER_ROLE check succeeds if Alice has the role ✓
// 6. Tokens are minted successfully ✓

This fix enables the intended gasless transaction functionality for users while maintaining proper role-based access control.

This matches the implementation currently in OWPIdentity and:

  1. Recovers the original sender's address when the contract calls itself (meta-transaction case)

  2. Returns the regular msg.sender for direct calls

  3. Works in conjunction with the existing executeMetaTransaction function which appends the user's address to the calldata

The current implementation in OWPIdentity was implementing what should have been in the base contract. The fix is to move _msgSender() OWPIdentity implementation to NativeMetaTransaction where it belongs, and then have OWPIdentity either remove its implementation or properly override it.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
0xbrivan2 Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.