Skip to content

Commit 8311210

Browse files
committed
test: gas comparison logicalor vs multitoken
1 parent 220533d commit 8311210

File tree

3 files changed

+110
-108
lines changed

3 files changed

+110
-108
lines changed

src/enforcers/NativeTokenPeriodTransferEnforcer.sol

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol";
55

66
import { CaveatEnforcer } from "./CaveatEnforcer.sol";
77
import { ModeCode } from "../utils/Types.sol";
8-
import "forge-std/Test.sol";
98

109
/**
1110
* @title NativeTokenPeriodTransferEnforcer
@@ -170,10 +169,6 @@ contract NativeTokenPeriodTransferEnforcer is CaveatEnforcer {
170169
(, uint256 value_,) = _executionCallData.decodeSingle();
171170

172171
(uint256 periodAmount_, uint256 periodDuration_, uint256 startDate_) = getTermsInfo(_terms);
173-
console2.log("periodAmount_", periodAmount_);
174-
console2.log("periodDuration_", periodDuration_);
175-
console2.log("startDate_", startDate_);
176-
console2.log("block.timestamp", block.timestamp);
177172

178173
PeriodicAllowance storage allowance_ = periodicAllowances[msg.sender][_delegationHash];
179174

@@ -194,9 +189,6 @@ contract NativeTokenPeriodTransferEnforcer is CaveatEnforcer {
194189

195190
// Calculate available ETH using the current allowance state.
196191
(uint256 available_, bool isNewPeriod_, uint256 currentPeriod_) = _getAvailableAmount(allowance_);
197-
console2.log("available_", available_);
198-
console2.log("isNewPeriod_", isNewPeriod_);
199-
console2.log("currentPeriod_", currentPeriod_);
200192

201193
require(value_ <= available_, "NativeTokenPeriodTransferEnforcer:transfer-amount-exceeded");
202194

test/enforcers/GasComparison.t.sol

Lines changed: 81 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-License-Identifier: MIT AND Apache-2.0
22
pragma solidity 0.8.23;
33

4-
import "forge-std/Test.sol";
54
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
65
import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol";
76

@@ -15,6 +14,7 @@ import { NativeTokenPeriodTransferEnforcer } from "../../src/enforcers/NativeTok
1514
import { ERC20PeriodTransferEnforcer } from "../../src/enforcers/ERC20PeriodTransferEnforcer.sol";
1615
import { ExactCalldataEnforcer } from "../../src/enforcers/ExactCalldataEnforcer.sol";
1716
import { ValueLteEnforcer } from "../../src/enforcers/ValueLteEnforcer.sol";
17+
import "forge-std/Test.sol";
1818

1919
contract GasComparisonTest is CaveatEnforcerBaseTest {
2020
////////////////////////////// State //////////////////////////////
@@ -28,8 +28,9 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
2828
address[] public tokens;
2929

3030
// 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;
3334
uint256 constant PERIOD_AMOUNT = 1 ether;
3435
uint256 constant PERIOD_DURATION = 1 days;
3536
uint256 startDate;
@@ -54,7 +55,12 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
5455
// Fills the first 5 elements with erc20, the rest with native
5556
for (uint256 i = 0; i < NUM_ERC20; i++) {
5657
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+
)
5864
);
5965
}
6066

@@ -68,7 +74,7 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
6874
vm.deal(address(this), 100 ether);
6975

7076
// Set block timestamp to start date
71-
// vm.warp(START_DATE);
77+
vm.warp(block.timestamp + 1 days);
7278
startDate = block.timestamp;
7379
}
7480

@@ -115,9 +121,9 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
115121
////////////////////// Test Cases //////////////////////
116122

117123
/// @notice Tests gas usage for LogicalOrWrapperEnforcer with 10 token configurations
118-
function test_GasUsageLogicalOrWrapper() public {
124+
function test_gasUsageLogicalOrWrapper() public {
119125
// 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);
121127

122128
address[] memory erc20Enforcers = new address[](2);
123129
erc20Enforcers[0] = address(erc20TokenEnforcer);
@@ -159,6 +165,8 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
159165
// Sign the delegation with Alice's key
160166
delegation_ = signDelegation(users.alice, delegation_);
161167

168+
uint256 totalGasUsed = 0;
169+
162170
for (uint256 i = 0; i < tokens.length; i++) {
163171
LogicalOrWrapperEnforcer.SelectedGroup memory selectedGroup_ = _createSelectedGroup(i, new bytes[](2));
164172

@@ -168,42 +176,46 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
168176
Delegation[] memory delegations_ = new Delegation[](1);
169177
delegations_[0] = delegation_;
170178

171-
// uint256 balanceBefore = _getBalance(tokens[i], RECIPIENT);
179+
uint256 balanceBefore = _getBalance(tokens[i], RECIPIENT);
172180

181+
// Measure gas usage
182+
uint256 gasStart = gasleft();
173183
// Have Bob redeem the delegation
174184
invokeDelegation_UserOp(users.bob, delegations_, _getExecution(tokens[i], RECIPIENT, PERIOD_AMOUNT / 2));
185+
uint256 gasUsed = gasStart - gasleft();
186+
totalGasUsed += gasUsed;
175187

176-
// uint256 balanceAfter = _getBalance(tokens[i], RECIPIENT);
188+
uint256 balanceAfter = _getBalance(tokens[i], RECIPIENT);
177189

178-
// assertEq(balanceAfter, balanceBefore + PERIOD_AMOUNT / 2, "Balance not transferred");
190+
assertEq(balanceAfter, balanceBefore + PERIOD_AMOUNT / 2, "Balance not transferred");
179191
}
180-
}
181192

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);
188194
}
189195

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+
);
195212
}
196-
}
197213

198-
function createAndRedeemDelegation() internal {
199-
// Create a simple delegation from Alice to Bob
214+
// Create a single caveat with the MultiTokenPeriodEnforcer
200215
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"" });
206217

218+
// Create the delegation
207219
Delegation memory delegation_ = Delegation({
208220
delegator: address(users.alice.deleGator),
209221
delegate: address(users.bob.deleGator),
@@ -216,51 +228,49 @@ contract GasComparisonTest is CaveatEnforcerBaseTest {
216228
// Sign the delegation with Alice's key
217229
delegation_ = signDelegation(users.alice, delegation_);
218230

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);
221252

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+
}
225255

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);
228257
}
229258

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+
}
264274

265275
function _getEnforcer() internal view override returns (ICaveatEnforcer) {
266276
return ICaveatEnforcer(address(multiTokenEnforcer));

test/enforcers/LogicalOrWrapperEnforcer.t.sol

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -61,35 +61,6 @@ contract LogicalOrWrapperEnforcerTest is CaveatEnforcerBaseTest {
6161
vm.label(address(limitedCallsEnforcer), "Limited Calls Enforcer");
6262
}
6363

64-
////////////////////// Helper Functions //////////////////////
65-
66-
function _createCaveatGroup(
67-
address[] memory _enforcers,
68-
bytes[] memory _terms
69-
)
70-
internal
71-
pure
72-
returns (LogicalOrWrapperEnforcer.CaveatGroup memory)
73-
{
74-
require(_enforcers.length == _terms.length, "LogicalOrWrapperEnforcerTest:invalid-input-length");
75-
Caveat[] memory caveats = new Caveat[](_enforcers.length);
76-
for (uint256 i = 0; i < _enforcers.length; ++i) {
77-
caveats[i] = Caveat({ enforcer: _enforcers[i], terms: _terms[i], args: hex"" });
78-
}
79-
return LogicalOrWrapperEnforcer.CaveatGroup({ caveats: caveats });
80-
}
81-
82-
function _createSelectedGroup(
83-
uint256 _groupIndex,
84-
bytes[] memory _caveatArgs
85-
)
86-
internal
87-
pure
88-
returns (LogicalOrWrapperEnforcer.SelectedGroup memory)
89-
{
90-
return LogicalOrWrapperEnforcer.SelectedGroup({ groupIndex: _groupIndex, caveatArgs: _caveatArgs });
91-
}
92-
9364
////////////////////// Valid cases //////////////////////
9465

9566
/// @notice Tests that a single caveat group with one caveat works correctly by verifying that a group with a single allowed
@@ -813,6 +784,35 @@ contract LogicalOrWrapperEnforcerTest is CaveatEnforcerBaseTest {
813784
);
814785
}
815786

787+
////////////////////// Helper Functions //////////////////////
788+
789+
function _createCaveatGroup(
790+
address[] memory _enforcers,
791+
bytes[] memory _terms
792+
)
793+
internal
794+
pure
795+
returns (LogicalOrWrapperEnforcer.CaveatGroup memory)
796+
{
797+
require(_enforcers.length == _terms.length, "LogicalOrWrapperEnforcerTest:invalid-input-length");
798+
Caveat[] memory caveats = new Caveat[](_enforcers.length);
799+
for (uint256 i = 0; i < _enforcers.length; ++i) {
800+
caveats[i] = Caveat({ enforcer: _enforcers[i], terms: _terms[i], args: hex"" });
801+
}
802+
return LogicalOrWrapperEnforcer.CaveatGroup({ caveats: caveats });
803+
}
804+
805+
function _createSelectedGroup(
806+
uint256 _groupIndex,
807+
bytes[] memory _caveatArgs
808+
)
809+
internal
810+
pure
811+
returns (LogicalOrWrapperEnforcer.SelectedGroup memory)
812+
{
813+
return LogicalOrWrapperEnforcer.SelectedGroup({ groupIndex: _groupIndex, caveatArgs: _caveatArgs });
814+
}
815+
816816
function _getEnforcer() internal view override returns (ICaveatEnforcer) {
817817
return ICaveatEnforcer(address(logicalOrWrapperEnforcer));
818818
}

0 commit comments

Comments
 (0)