Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/unlucky-beans-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': patch
---

`ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes).
2 changes: 1 addition & 1 deletion contracts/metatx/ERC2771Context.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ abstract contract ERC2771Context is Context {
}

function _msgSender() internal view virtual override returns (address sender) {
if (isTrustedForwarder(msg.sender)) {
if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) {
// The assembly code is more direct than the Solidity version using `abi.decode`.
/// @solidity memory-safe-assembly
assembly {
Expand Down
11 changes: 11 additions & 0 deletions test/metatx/ERC2771Context.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const ContextMockCaller = artifacts.require('ContextMockCaller');
const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior');

contract('ERC2771Context', function (accounts) {
const [, anotherAccount] = accounts;

const MAX_UINT48 = web3.utils.toBN(1).shln(48).subn(1).toString();

beforeEach(async function () {
Expand Down Expand Up @@ -79,6 +81,15 @@ contract('ERC2771Context', function (accounts) {
const { tx } = await this.forwarder.execute(req);
await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender });
});

it('returns the original sender when calldata length is less than 20 bytes (address length)', async function () {
// The forwarder doesn't produce calls with calldata length less than 20 bytes
const recipient = await ERC2771ContextMock.new(anotherAccount);

const { receipt } = await recipient.msgSender({ from: anotherAccount });

await expectEvent(receipt, 'Sender', { sender: anotherAccount });
});
});

describe('msgData', function () {
Expand Down