Skip to content

Commit 1bc3f03

Browse files
committed
update relayer call to revert if calldata is too short
1 parent 10c835d commit 1bc3f03

File tree

2 files changed

+80
-54
lines changed

2 files changed

+80
-54
lines changed

contracts/utils/RelayedCall.sol

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,46 +40,55 @@ abstract contract RelayedCall {
4040
}
4141

4242
function _deployRelayer() private returns (address addr) {
43-
// deployment prefix: 3d602480600a3d3981f3
44-
// deployed bytecode: 6014360360145f375f5f601436035f345f3560601c5af13d5f5f3e5f3d91602257fd5bf3
43+
// deployment prefix: 3d602f80600a3d3981f3
44+
// deployed bytecode: 60133611600a575f5ffd5b6014360360145f375f5f601436035f345f3560601c5af13d5f5f3e5f3d91602d57fd5bf3
4545
//
4646
// offset | bytecode | opcode | stack
4747
// -------|----------|----------------|--------
48-
// 0x0000 | 6014 | push1 0x14 | 0x14
49-
// 0x0002 | 36 | calldatasize | cds 0x14
50-
// 0x0003 | 03 | sub | (cds-0x14)
51-
// 0x0004 | 6014 | push1 0x14 | 0x14 (cds-0x14)
52-
// 0x0006 | 5f | push0 | 0 0x14 (cds-0x14)
53-
// 0x0007 | 37 | calldatacopy |
54-
// 0x0008 | 5f | push0 | 0
55-
// 0x0009 | 5f | push0 | 0 0
56-
// 0x000a | 6014 | push1 0x14 | 0x14 0 0
57-
// 0x000c | 36 | calldatasize | cds 0x14 0 0
58-
// 0x000d | 03 | sub | (cds-0x14) 0 0
59-
// 0x000e | 5f | push0 | 0 (cds-0x14) 0 0
60-
// 0x000f | 34 | callvalue | value 0 (cds-0x14) 0 0
61-
// 0x0010 | 5f | push0 | 0 value 0 (cds-0x14) 0 0
62-
// 0x0011 | 35 | calldataload | cd[0] value 0 (cds-0x14) 0 0
63-
// 0x0012 | 6060 | push1 0x60 | 0x60 cd[0] value 0 (cds-0x14) 0 0
64-
// 0x0014 | 1c | shr | target value 0 (cds-0x14) 0 0
65-
// 0x0015 | 5a | gas | gas target value 0 (cds-0x14) 0 0
66-
// 0x0016 | f1 | call | suc
67-
// 0x0017 | 3d | returndatasize | rds suc
68-
// 0x0018 | 5f | push0 | 0 rds suc
69-
// 0x0019 | 5f | push0 | 0 0 rds suc
70-
// 0x001a | 3e | returndatacopy | suc
71-
// 0x001b | 5f | push0 | 0 suc
72-
// 0x001c | 3d | returndatasize | rds 0 suc
73-
// 0x001d | 91 | swap2 | suc 0 rds
74-
// 0x001e | 6022 | push1 0x22 | 0x22 suc 0 rds
75-
// 0x0020 | 57 | jumpi | 0 rds
76-
// 0x0021 | fd | revert |
77-
// 0x0022 | 5b | jumpdest | 0 rds
78-
// 0x0023 | f3 | return |
48+
// 0x0000 | 6013 | push1 0x13 | 0x13
49+
// 0x0002 | 36 | calldatasize | cds 0x13
50+
// 0x0003 | 11 | gt | (cds>0x13)
51+
// 0x0004 | 600a | push1 0x0a | 0x0a (cds>0x13)
52+
// 0x0006 | 57 | jumpi | 0x0a (cds>0x13)
53+
// 0x0007 | 5f | push0 | 0
54+
// 0x0008 | 5f | push0 | 0 0
55+
// 0x0009 | fd | revert |
56+
// 0x000a | 5b | jumpdest |
57+
// 0x000b | 6014 | push1 0x14 | 0x14
58+
// 0x000d | 36 | calldatasize | cds 0x14
59+
// 0x000e | 03 | sub | (cds-0x14)
60+
// 0x000f | 6014 | push1 0x14 | 0x14 (cds-0x14)
61+
// 0x0011 | 5f | push0 | 0 0x14 (cds-0x14)
62+
// 0x0012 | 37 | calldatacopy |
63+
// 0x0013 | 5f | push0 | 0
64+
// 0x0014 | 5f | push0 | 0 0
65+
// 0x0015 | 6014 | push1 0x14 | 0x14 0 0
66+
// 0x0017 | 36 | calldatasize | cds 0x14 0 0
67+
// 0x0018 | 03 | sub | (cds-0x14) 0 0
68+
// 0x0019 | 5f | push0 | 0 (cds-0x14) 0 0
69+
// 0x001a | 34 | callvalue | value 0 (cds-0x14) 0 0
70+
// 0x001b | 5f | push0 | 0 value 0 (cds-0x14) 0 0
71+
// 0x001c | 35 | calldataload | cd[0] value 0 (cds-0x14) 0 0
72+
// 0x001d | 6060 | push1 0x60 | 0x60 cd[0] value 0 (cds-0x14) 0 0
73+
// 0x001f | 1c | shr | target value 0 (cds-0x14) 0 0
74+
// 0x0020 | 5a | gas | gas target value 0 (cds-0x14) 0 0
75+
// 0x0021 | f1 | call | suc
76+
// 0x0022 | 3d | returndatasize | rds suc
77+
// 0x0023 | 5f | push0 | 0 rds suc
78+
// 0x0024 | 5f | push0 | 0 0 rds suc
79+
// 0x0025 | 3e | returndatacopy | suc
80+
// 0x0026 | 5f | push0 | 0 suc
81+
// 0x0027 | 3d | returndatasize | rds 0 suc
82+
// 0x0028 | 91 | swap2 | suc 0 rds
83+
// 0x0029 | 602d | push1 0x2d | 0x2d suc 0 rds
84+
// 0x002b | 57 | jumpi | 0 rds
85+
// 0x002c | fd | revert |
86+
// 0x002d | 5b | jumpdest | 0 rds
87+
// 0x002e | f3 | return |
7988
assembly ("memory-safe") {
80-
mstore(0x0e, 0xf13d5f5f3e5f3d91602257fd5bf3)
81-
mstore(0x00, 0x3d602480600a3d3981f36014360360145f375f5f601436035f345f3560601c5a)
82-
addr := create2(0, 0, 0x2f, 0)
89+
mstore(0x19, 0x1436035f345f3560601c5af13d5f5f3e5f3d91602d57fd5bf3)
90+
mstore(0x00, 0x3d602f80600a3d3981f360133611600a575f5ffd5b6014360360145f375f5f60)
91+
addr := create2(0, 0, 0x39, 0)
8392
if iszero(addr) {
8493
let ptr := mload(0x40)
8594
returndatacopy(ptr, 0, returndatasize())

test/utils/RelayedCall.test.js

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,44 @@ describe('RelayedCall', function () {
1919
Object.assign(this, await loadFixture(fixture));
2020
});
2121

22-
it('call success', async function () {
23-
await expect(
24-
this.mock.$_relayedCallStrict(this.target, this.target.interface.encodeFunctionData('fnUnrestricted', [])),
25-
)
26-
.to.emit(this.target, 'CalledUnrestricted')
27-
.withArgs(this.relayer);
22+
describe('relayed call', function () {
23+
it('target success', async function () {
24+
await expect(
25+
this.mock.$_relayedCallStrict(this.target, this.target.interface.encodeFunctionData('fnUnrestricted', [])),
26+
)
27+
.to.emit(this.target, 'CalledUnrestricted')
28+
.withArgs(this.relayer);
29+
});
30+
31+
it('target success (with value)', async function () {
32+
const value = 42n;
33+
await expect(this.mock.$_relayedCallStrict(this.receiver, value, '0x', { value })).to.changeEtherBalances(
34+
[this.mock, this.relayer, this.receiver],
35+
[0n, 0n, value],
36+
);
37+
});
38+
39+
it('target revert', async function () {
40+
await expect(
41+
this.mock.$_relayedCallStrict(this.target, this.target.interface.encodeFunctionData('fnRestricted', [])),
42+
)
43+
.to.be.revertedWithCustomError(this.target, 'AccessManagedUnauthorized')
44+
.withArgs(this.relayer);
45+
});
2846
});
2947

30-
it('call success with value', async function () {
31-
const value = 42n;
32-
await expect(this.mock.$_relayedCallStrict(this.receiver, value, '0x', { value })).to.changeEtherBalances(
33-
[this.mock, this.relayer, this.receiver],
34-
[0n, 0n, value],
35-
);
36-
});
48+
it('direct call to the relayer', async function () {
49+
// 20 bytes (address + empty data) - OK
50+
await expect(
51+
this.mock.runner.sendTransaction({ to: this.relayer, data: '0x7859821024E633C5dC8a4FcF86fC52e7720Ce525' }),
52+
).to.not.be.reverted;
3753

38-
it('call failure', async function () {
54+
// 19 bytes (not enough for an address) - REVERT
3955
await expect(
40-
this.mock.$_relayedCallStrict(this.target, this.target.interface.encodeFunctionData('fnRestricted', [])),
41-
)
42-
.to.be.revertedWithCustomError(this.target, 'AccessManagedUnauthorized')
43-
.withArgs(this.relayer);
56+
this.mock.runner.sendTransaction({ to: this.relayer, data: '0x7859821024E633C5dC8a4FcF86fC52e7720Ce5' }),
57+
).to.be.revertedWithoutReason();
58+
59+
// 0 bytes (not enough for an address) - REVERT
60+
await expect(this.mock.runner.sendTransaction({ to: this.relayer, data: '0x' })).to.be.revertedWithoutReason();
4461
});
4562
});

0 commit comments

Comments
 (0)