22pragma solidity ^ 0.8.4 ;
33
44import "../../utils/SoladyTest.sol " ;
5- import {ERC7821 , MockERC7821} from "../../utils/mocks/MockERC7821.sol " ;
5+ import {ERC7821 , MockERC7821} from "../../utils/mocks/ext/ithaca/ MockERC7821.sol " ;
66import {LibClone} from "../../../src/utils/LibClone.sol " ;
77
88contract ERC7821Test is SoladyTest {
@@ -13,7 +13,7 @@ contract ERC7821Test is SoladyTest {
1313 address target;
1414
1515 bytes32 internal constant _SUPPORTED_MODE = bytes10 (0x01000000000078210001 );
16-
16+ bytes32 internal constant _OPTIMIZED_BATCH_MODE = bytes10 ( 0x01000000000078210003 );
1717 bytes [] internal _bytes;
1818
1919 function setUp () public {
@@ -54,6 +54,21 @@ contract ERC7821Test is SoladyTest {
5454 mbe.execute {value: _totalValue (calls)}(_SUPPORTED_MODE, data);
5555 }
5656
57+ function testERC7821OptimizedBatchGas () public {
58+ vm.pauseGasMetering ();
59+ vm.deal (address (this ), 1 ether);
60+
61+ bytes [] memory dataArr = new bytes [](2 );
62+
63+ dataArr[0 ] = abi.encodeWithSignature ("returnsBytes(bytes) " , "hehe " );
64+ dataArr[1 ] = abi.encodeWithSignature ("returnsHash(bytes) " , "lol " );
65+
66+ bytes memory data = abi.encode (target, dataArr);
67+ vm.resumeGasMetering ();
68+
69+ mbe.execute (_OPTIMIZED_BATCH_MODE, data);
70+ }
71+
5772 function testERC7821 (bytes memory opData ) public {
5873 vm.deal (address (this ), 1 ether);
5974
@@ -72,6 +87,18 @@ contract ERC7821Test is SoladyTest {
7287 assertEq (mbe.lastOpData (), opData);
7388 }
7489
90+ function testERC7821OptimizedBatch (bytes memory opData ) public {
91+ vm.deal (address (this ), 1 ether);
92+
93+ bytes [] memory dataArr = new bytes [](2 );
94+ dataArr[0 ] = abi.encodeWithSignature ("returnsBytes(bytes) " , "hehe " );
95+ dataArr[1 ] = abi.encodeWithSignature ("returnsHash(bytes) " , "lol " );
96+
97+ mbe.execute (_OPTIMIZED_BATCH_MODE, _encodeOptimizedBatch (target, dataArr, opData));
98+
99+ assertEq (mbe.lastOpData (), opData);
100+ }
101+
75102 function testERC7821ForRevert () public {
76103 ERC7821 .Call[] memory calls = new ERC7821 .Call [](1 );
77104 calls[0 ].to = target;
@@ -82,6 +109,14 @@ contract ERC7821Test is SoladyTest {
82109 mbe.execute {value: _totalValue (calls)}(_SUPPORTED_MODE, _encode (calls, "" ));
83110 }
84111
112+ function testERC7821OptimizedBatchForRevert () public {
113+ bytes [] memory dataArr = new bytes [](1 );
114+ dataArr[0 ] = abi.encodeWithSignature ("revertsWithCustomError() " );
115+
116+ vm.expectRevert (CustomError.selector );
117+ mbe.execute (_OPTIMIZED_BATCH_MODE, _encodeOptimizedBatch (target, dataArr, "" ));
118+ }
119+
85120 function _encode (ERC7821 .Call[] memory calls , bytes memory opData )
86121 internal
87122 returns (bytes memory )
@@ -90,6 +125,14 @@ contract ERC7821Test is SoladyTest {
90125 return abi.encode (calls, opData);
91126 }
92127
128+ function _encodeOptimizedBatch (address to , bytes [] memory dataArr , bytes memory opData )
129+ internal
130+ returns (bytes memory )
131+ {
132+ if (_randomChance (2 ) && opData.length == 0 ) return abi.encode (to, dataArr);
133+ return abi.encode (to, dataArr, opData);
134+ }
135+
93136 struct Payload {
94137 bytes data;
95138 uint256 mode;
@@ -125,6 +168,34 @@ contract ERC7821Test is SoladyTest {
125168 }
126169 }
127170
171+ function testERC7821OptimizedBatch (bytes32 ) public {
172+ vm.deal (address (this ), 1 ether);
173+
174+ bytes [] memory dataArr = new bytes [](_randomUniform () & 3 );
175+ Payload[] memory payloads = new Payload [](dataArr.length );
176+
177+ for (uint256 i; i < dataArr.length ; ++ i) {
178+ bytes memory data = _truncateBytes (_randomBytes (), 0x1ff );
179+ payloads[i].data = data;
180+ if (_randomChance (2 )) {
181+ payloads[i].mode = 0 ;
182+ dataArr[i] = abi.encodeWithSignature ("returnsBytes(bytes) " , data);
183+ } else {
184+ payloads[i].mode = 1 ;
185+ dataArr[i] = abi.encodeWithSignature ("returnsHash(bytes) " , data);
186+ }
187+ }
188+
189+ mbe.executeDirect (target, dataArr);
190+
191+ if (dataArr.length != 0 && _randomChance (32 )) {
192+ dataArr[_randomUniform () % dataArr.length ] =
193+ abi.encodeWithSignature ("revertsWithCustomError() " );
194+ vm.expectRevert (CustomError.selector );
195+ mbe.executeDirect (target, dataArr);
196+ }
197+ }
198+
128199 function _totalValue (ERC7821 .Call[] memory calls ) internal pure returns (uint256 result ) {
129200 unchecked {
130201 for (uint256 i; i < calls.length ; ++ i) {
@@ -182,4 +253,18 @@ contract ERC7821Test is SoladyTest {
182253 function pushBytes (bytes memory x ) public {
183254 _bytes.push (x);
184255 }
256+
257+ function testERC7821OptimizedBatchWithZeroAddress () public {
258+ // Test that when to=address(0), it gets replaced with address(this) (the MockERC7821 contract)
259+ // We'll call executeDirect which directly calls the internal _execute function
260+ bytes [] memory dataArr = new bytes [](1 );
261+ dataArr[0 ] =
262+ abi.encodeWithSignature ("setAuthorizedCaller(address,bool) " , address (0x123 ), true );
263+
264+ // This should replace address(0) with address(mbe) and call setAuthorizedCaller on itself
265+ mbe.executeDirect (address (0 ), dataArr);
266+
267+ // Verify the call succeeded by checking that address(0x123) is now authorized
268+ assertTrue (mbe.isAuthorizedCaller (address (0x123 )));
269+ }
185270}
0 commit comments