Skip to content

Commit 952775e

Browse files
authored
Implement ERC-7821 calldata compression in ERC7579Utils (#5602)
1 parent a31b4a4 commit 952775e

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

contracts/account/utils/draft-ERC7579Utils.sol

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ library ERC7579Utils {
218218
uint256 value,
219219
bytes calldata data
220220
) private returns (bytes memory) {
221-
(bool success, bytes memory returndata) = target.call{value: value}(data);
221+
(bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).call{value: value}(
222+
data
223+
);
222224
return _validateExecutionMode(index, execType, success, returndata);
223225
}
224226

@@ -229,7 +231,7 @@ library ERC7579Utils {
229231
address target,
230232
bytes calldata data
231233
) private returns (bytes memory) {
232-
(bool success, bytes memory returndata) = target.delegatecall(data);
234+
(bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).delegatecall(data);
233235
return _validateExecutionMode(index, execType, success, returndata);
234236
}
235237

test/account/utils/draft-ERC7579Utils.test.js

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ const { ethers } = require('hardhat');
22
const { expect } = require('chai');
33
const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
44
const {
5+
CALL_TYPE_CALL,
6+
CALL_TYPE_BATCH,
7+
CALL_TYPE_DELEGATE,
58
EXEC_TYPE_DEFAULT,
69
EXEC_TYPE_TRY,
710
encodeSingle,
811
encodeBatch,
912
encodeDelegate,
10-
CALL_TYPE_CALL,
11-
CALL_TYPE_BATCH,
1213
encodeMode,
1314
} = require('../../helpers/erc7579');
1415
const { selector } = require('../../helpers/methods');
@@ -29,6 +30,14 @@ describe('ERC7579Utils', function () {
2930
Object.assign(this, await loadFixture(fixture));
3031
});
3132

33+
it('constants', async function () {
34+
await expect(this.utils.$CALLTYPE_SINGLE()).to.eventually.equal(CALL_TYPE_CALL);
35+
await expect(this.utils.$CALLTYPE_BATCH()).to.eventually.equal(CALL_TYPE_BATCH);
36+
await expect(this.utils.$CALLTYPE_DELEGATECALL()).to.eventually.equal(CALL_TYPE_DELEGATE);
37+
await expect(this.utils.$EXECTYPE_DEFAULT()).to.eventually.equal(EXEC_TYPE_DEFAULT);
38+
await expect(this.utils.$EXECTYPE_TRY()).to.eventually.equal(EXEC_TYPE_TRY);
39+
});
40+
3241
describe('execSingle', function () {
3342
it('calls the target with value', async function () {
3443
const value = 0x012;
@@ -54,6 +63,18 @@ describe('ERC7579Utils', function () {
5463
await expect(ethers.provider.getBalance(this.target)).to.eventually.equal(value);
5564
});
5665

66+
it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () {
67+
const data = encodeSingle(
68+
ethers.ZeroAddress, // address(0)
69+
0,
70+
this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', []),
71+
);
72+
73+
await expect(this.utils.$execSingle(data, EXEC_TYPE_DEFAULT))
74+
.to.emit(this.utils, 'return$execSingle')
75+
.withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32)]);
76+
});
77+
5778
it('reverts when target reverts in default ExecType', async function () {
5879
const value = 0x012;
5980
const data = encodeSingle(
@@ -131,6 +152,17 @@ describe('ERC7579Utils', function () {
131152
await expect(ethers.provider.getBalance(this.anotherTarget)).to.eventually.equal(value2);
132153
});
133154

155+
it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () {
156+
const data = encodeBatch(
157+
[ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_SINGLE', [])],
158+
[ethers.ZeroAddress, 0, this.utils.interface.encodeFunctionData('$CALLTYPE_BATCH', [])],
159+
);
160+
161+
await expect(this.utils.$execBatch(data, EXEC_TYPE_DEFAULT))
162+
.to.emit(this.utils, 'return$execBatch')
163+
.withArgs([ethers.zeroPadBytes(CALL_TYPE_CALL, 32), ethers.zeroPadBytes(CALL_TYPE_BATCH, 32)]);
164+
});
165+
134166
it('reverts when any target reverts in default ExecType', async function () {
135167
const value1 = 0x012;
136168
const value2 = 0x234;
@@ -193,6 +225,17 @@ describe('ERC7579Utils', function () {
193225
await expect(ethers.provider.getStorage(this.utils.target, slot)).to.eventually.equal(value);
194226
});
195227

228+
it('default to calling self is target is address(0) (ERC-7821 calldata compression)', async function () {
229+
const data = encodeDelegate(
230+
ethers.ZeroAddress,
231+
this.utils.interface.encodeFunctionData('$CALLTYPE_DELEGATECALL', []),
232+
);
233+
234+
await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT))
235+
.to.emit(this.utils, 'return$execDelegateCall')
236+
.withArgs([ethers.zeroPadBytes(CALL_TYPE_DELEGATE, 32)]);
237+
});
238+
196239
it('reverts when target reverts in default ExecType', async function () {
197240
const data = encodeDelegate(this.target, this.target.interface.encodeFunctionData('mockFunctionRevertsReason'));
198241
await expect(this.utils.$execDelegateCall(data, EXEC_TYPE_DEFAULT)).to.be.revertedWith(

0 commit comments

Comments
 (0)