Skip to content
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

Adjust ERC2771Context._msgData for msg.data.length < 20 #4484

Merged
merged 3 commits into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

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

`ERC2771Context`: Prevent revert in `_msgData()` when 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). Return the full calldata in that case.
2 changes: 1 addition & 1 deletion contracts/metatx/ERC2771Context.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ abstract contract ERC2771Context is Context {
}

function _msgData() internal view virtual override returns (bytes calldata) {
if (isTrustedForwarder(msg.sender)) {
if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) {
return msg.data[:msg.data.length - 20];
} else {
return super._msgData();
Expand Down
6 changes: 6 additions & 0 deletions contracts/mocks/ContextMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ contract ContextMock is Context {
function msgData(uint256 integerValue, string memory stringValue) public {
emit Data(_msgData(), integerValue, stringValue);
}

event DataShort(bytes data);

function msgDataShort() public {
emit DataShort(_msgData());
}
}

contract ContextMockCaller {
Expand Down
18 changes: 14 additions & 4 deletions test/metatx/ERC2771Context.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const ContextMockCaller = artifacts.require('ContextMockCaller');
const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior');

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

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

Expand Down Expand Up @@ -84,11 +84,11 @@ contract('ERC2771Context', function (accounts) {

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 recipient = await ERC2771ContextMock.new(trustedForwarder);

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

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

Expand Down Expand Up @@ -117,5 +117,15 @@ contract('ERC2771Context', function (accounts) {
await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue });
});
});

it('returns the full original data 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(trustedForwarder);

const { receipt } = await recipient.msgDataShort({ from: trustedForwarder });

const data = recipient.contract.methods.msgDataShort().encodeABI();
await expectEvent(receipt, 'DataShort', { data });
});
});
});