1
1
// SPDX-License-Identifier: MIT AND Apache-2.0
2
2
pragma solidity 0.8.23 ;
3
3
4
- import "forge-std/Test.sol " ;
5
4
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol " ;
6
5
import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol " ;
7
6
@@ -15,6 +14,7 @@ import { NativeTokenPeriodTransferEnforcer } from "../../src/enforcers/NativeTok
15
14
import { ERC20PeriodTransferEnforcer } from "../../src/enforcers/ERC20PeriodTransferEnforcer.sol " ;
16
15
import { ExactCalldataEnforcer } from "../../src/enforcers/ExactCalldataEnforcer.sol " ;
17
16
import { ValueLteEnforcer } from "../../src/enforcers/ValueLteEnforcer.sol " ;
17
+ import "forge-std/Test.sol " ;
18
18
19
19
contract GasComparisonTest is CaveatEnforcerBaseTest {
20
20
////////////////////////////// State //////////////////////////////
@@ -28,8 +28,9 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
28
28
address [] public tokens;
29
29
30
30
// Constants for test configuration
31
- uint256 constant NUM_NATIVE = 5 ;
32
- uint256 constant NUM_ERC20 = 5 ;
31
+ uint256 constant AMOUNT_PER_TOKEN = 5 ;
32
+ uint256 constant NUM_NATIVE = AMOUNT_PER_TOKEN;
33
+ uint256 constant NUM_ERC20 = AMOUNT_PER_TOKEN;
33
34
uint256 constant PERIOD_AMOUNT = 1 ether ;
34
35
uint256 constant PERIOD_DURATION = 1 days ;
35
36
uint256 startDate;
@@ -54,7 +55,12 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
54
55
// Fills the first 5 elements with erc20, the rest with native
55
56
for (uint256 i = 0 ; i < NUM_ERC20; i++ ) {
56
57
tokens[i] = address (
57
- new BasicERC20 (address (this ), string (abi.encodePacked ("Token " , i)), string (abi.encodePacked ("TK " , i)), 100 ether)
58
+ new BasicERC20 (
59
+ address (users.alice.deleGator),
60
+ string (abi.encodePacked ("Token " , i)),
61
+ string (abi.encodePacked ("TK " , i)),
62
+ 100 ether
63
+ )
58
64
);
59
65
}
60
66
@@ -68,7 +74,7 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
68
74
vm.deal (address (this ), 100 ether);
69
75
70
76
// Set block timestamp to start date
71
- // vm.warp(START_DATE );
77
+ vm.warp (block . timestamp + 1 days );
72
78
startDate = block .timestamp ;
73
79
}
74
80
@@ -115,9 +121,9 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
115
121
////////////////////// Test Cases //////////////////////
116
122
117
123
/// @notice Tests gas usage for LogicalOrWrapperEnforcer with 10 token configurations
118
- function test_GasUsageLogicalOrWrapper () public {
124
+ function test_gasUsageLogicalOrWrapper () public {
119
125
// Create caveat groups
120
- LogicalOrWrapperEnforcer.CaveatGroup[] memory groups = new LogicalOrWrapperEnforcer.CaveatGroup [](NUM_NATIVE + NUM_ERC20 );
126
+ LogicalOrWrapperEnforcer.CaveatGroup[] memory groups = new LogicalOrWrapperEnforcer.CaveatGroup [](tokens. length );
121
127
122
128
address [] memory erc20Enforcers = new address [](2 );
123
129
erc20Enforcers[0 ] = address (erc20TokenEnforcer);
@@ -159,6 +165,8 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
159
165
// Sign the delegation with Alice's key
160
166
delegation_ = signDelegation (users.alice, delegation_);
161
167
168
+ uint256 totalGasUsed = 0 ;
169
+
162
170
for (uint256 i = 0 ; i < tokens.length ; i++ ) {
163
171
LogicalOrWrapperEnforcer.SelectedGroup memory selectedGroup_ = _createSelectedGroup (i, new bytes [](2 ));
164
172
@@ -168,42 +176,46 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
168
176
Delegation[] memory delegations_ = new Delegation [](1 );
169
177
delegations_[0 ] = delegation_;
170
178
171
- // uint256 balanceBefore = _getBalance(tokens[i], RECIPIENT);
179
+ uint256 balanceBefore = _getBalance (tokens[i], RECIPIENT);
172
180
181
+ // Measure gas usage
182
+ uint256 gasStart = gasleft ();
173
183
// Have Bob redeem the delegation
174
184
invokeDelegation_UserOp (users.bob, delegations_, _getExecution (tokens[i], RECIPIENT, PERIOD_AMOUNT / 2 ));
185
+ uint256 gasUsed = gasStart - gasleft ();
186
+ totalGasUsed += gasUsed;
175
187
176
- // uint256 balanceAfter = _getBalance(tokens[i], RECIPIENT);
188
+ uint256 balanceAfter = _getBalance (tokens[i], RECIPIENT);
177
189
178
- // assertEq(balanceAfter, balanceBefore + PERIOD_AMOUNT / 2, "Balance not transferred");
190
+ assertEq (balanceAfter, balanceBefore + PERIOD_AMOUNT / 2 , "Balance not transferred " );
179
191
}
180
- }
181
192
182
- function _getBalance (address token_ , address recipient_ ) internal view returns (uint256 ) {
183
- if (token_ == address (0 )) {
184
- return recipient_.balance;
185
- } else {
186
- return IERC20 (token_).balanceOf (recipient_);
187
- }
193
+ console2.log ("LogicalOrWrapper Total Gas Used: " , totalGasUsed, " Amount of tokens: " , tokens.length );
188
194
}
189
195
190
- function _getExecution (address token_ , address recipient_ , uint256 amount_ ) internal pure returns (Execution memory ) {
191
- if (token_ == address (0 )) {
192
- return Execution ({ target: recipient_, value: amount_, callData: hex "" });
193
- } else {
194
- return Execution ({ target: token_, value: 0 , callData: _encodeERC20Transfer (recipient_, amount_) });
196
+ /// @notice Tests gas usage for MultiTokenPeriodEnforcer with 10 token configurations
197
+ function test_gasUsageMultiTokenPeriod () public {
198
+ // Create terms for all tokens (5 ERC20 + 5 native)
199
+ bytes memory terms;
200
+ for (uint256 i = 0 ; i < tokens.length ; i++ ) {
201
+ // For each token, append a 116-byte configuration
202
+ // TODO: IF THIS DOESN'T WORK, TRY TO USE THE blob_ = abi.encodePacked(blob_,
203
+ terms = bytes .concat (
204
+ terms,
205
+ abi.encodePacked (
206
+ tokens[i], // token address (address(0) for native)
207
+ PERIOD_AMOUNT, // period amount
208
+ PERIOD_DURATION, // period duration
209
+ startDate // start date
210
+ )
211
+ );
195
212
}
196
- }
197
213
198
- function createAndRedeemDelegation () internal {
199
- // Create a simple delegation from Alice to Bob
214
+ // Create a single caveat with the MultiTokenPeriodEnforcer
200
215
Caveat[] memory caveats_ = new Caveat [](1 );
201
- caveats_[0 ] = Caveat ({
202
- enforcer: address (logicalOrWrapperEnforcer),
203
- terms: abi.encodePacked (address (0 ), PERIOD_AMOUNT, PERIOD_DURATION, startDate),
204
- args: hex ""
205
- });
216
+ caveats_[0 ] = Caveat ({ enforcer: address (multiTokenEnforcer), terms: terms, args: hex "" });
206
217
218
+ // Create the delegation
207
219
Delegation memory delegation_ = Delegation ({
208
220
delegator: address (users.alice.deleGator),
209
221
delegate: address (users.bob.deleGator),
@@ -216,51 +228,49 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
216
228
// Sign the delegation with Alice's key
217
229
delegation_ = signDelegation (users.alice, delegation_);
218
230
219
- // Create execution for Bob to redeem
220
- Execution memory execution_ = Execution ({ target: RECIPIENT, value: PERIOD_AMOUNT / 2 , callData: hex "" });
231
+ uint256 totalGasUsed = 0 ;
232
+
233
+ // Test redeeming the delegation for each token
234
+ for (uint256 i = 0 ; i < tokens.length ; i++ ) {
235
+ // Update args with the current token index
236
+ delegation_.caveats[0 ].args = abi.encode (i);
237
+
238
+ // Pack delegations into array
239
+ Delegation[] memory delegations_ = new Delegation [](1 );
240
+ delegations_[0 ] = delegation_;
241
+
242
+ uint256 balanceBefore = _getBalance (tokens[i], RECIPIENT);
243
+
244
+ // Measure gas usage
245
+ uint256 gasStart = gasleft ();
246
+ // Have Bob redeem the delegation
247
+ invokeDelegation_UserOp (users.bob, delegations_, _getExecution (tokens[i], RECIPIENT, PERIOD_AMOUNT / 2 ));
248
+ uint256 gasUsed = gasStart - gasleft ();
249
+ totalGasUsed += gasUsed;
250
+
251
+ uint256 balanceAfter = _getBalance (tokens[i], RECIPIENT);
221
252
222
- // Pack delegations into array
223
- Delegation[] memory delegations_ = new Delegation [](1 );
224
- delegations_[0 ] = delegation_;
253
+ assertEq (balanceAfter, balanceBefore + PERIOD_AMOUNT / 2 , "Balance not transferred " );
254
+ }
225
255
226
- // Have Bob redeem the delegation
227
- invokeDelegation_UserOp (users.bob, delegations_, execution_);
256
+ console2.log ("MultiTokenPeriod Total Gas Used: " , totalGasUsed, " Amount of tokens: " , tokens.length );
228
257
}
229
258
230
- // /// @notice Tests gas usage for MultiTokenPeriodEnforcer with 10 token configurations
231
- // function test_GasUsageMultiTokenPeriod() public {
232
- // // Create terms for all tokens (5 native + 5 ERC20)
233
- // bytes memory terms;
234
- // for (uint256 i = 0; i < NUM_NATIVE; i++) {
235
- // terms = bytes.concat(terms, abi.encodePacked(address(0), PERIOD_AMOUNT, PERIOD_DURATION, START_DATE));
236
- // }
237
- // for (uint256 i = 0; i < NUM_ERC20; i++) {
238
- // terms = bytes.concat(terms, abi.encodePacked(address(erc20Tokens[i]), PERIOD_AMOUNT, PERIOD_DURATION, START_DATE));
239
- // }
240
-
241
- // uint256 gasUsed = 0;
242
-
243
- // // Test native token transfers
244
- // for (uint256 i = 0; i < NUM_NATIVE; i++) {
245
- // bytes memory args = abi.encode(i);
246
- // bytes memory execData = _encodeNativeTransfer(address(0x123), PERIOD_AMOUNT / 2);
247
- // uint256 startGas = gasleft();
248
- // multiTokenEnforcer.beforeHook(terms, args, singleDefaultMode, execData, _dummyDelegationHash, address(0), _redeemer);
249
- // gasUsed += startGas - gasleft();
250
- // }
251
-
252
- // // Test ERC20 token transfers
253
- // for (uint256 i = 0; i < NUM_ERC20; i++) {
254
- // bytes memory args = abi.encode(NUM_NATIVE + i);
255
- // bytes memory callData = _encodeERC20Transfer(address(0x123), PERIOD_AMOUNT / 2);
256
- // bytes memory execData = _encodeSingleExecution(address(erc20Tokens[i]), 0, callData);
257
- // uint256 startGas = gasleft();
258
- // multiTokenEnforcer.beforeHook(terms, args, singleDefaultMode, execData, _dummyDelegationHash, address(0), _redeemer);
259
- // gasUsed += startGas - gasleft();
260
- // }
261
-
262
- // console2.log("Total gas used for MultiTokenPeriodEnforcer:", gasUsed);
263
- // }
259
+ function _getBalance (address token_ , address recipient_ ) internal view returns (uint256 ) {
260
+ if (token_ == address (0 )) {
261
+ return recipient_.balance;
262
+ } else {
263
+ return IERC20 (token_).balanceOf (recipient_);
264
+ }
265
+ }
266
+
267
+ function _getExecution (address token_ , address recipient_ , uint256 amount_ ) internal pure returns (Execution memory ) {
268
+ if (token_ == address (0 )) {
269
+ return Execution ({ target: recipient_, value: amount_, callData: hex "" });
270
+ } else {
271
+ return Execution ({ target: token_, value: 0 , callData: _encodeERC20Transfer (recipient_, amount_) });
272
+ }
273
+ }
264
274
265
275
function _getEnforcer () internal view override returns (ICaveatEnforcer) {
266
276
return ICaveatEnforcer (address (multiTokenEnforcer));
0 commit comments