From 146ecb5291f8fb47adf0fbf4b94bf1d2d3a310a1 Mon Sep 17 00:00:00 2001 From: Hanzel Anchia Mena <33629234+hanzel98@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:20:04 -0600 Subject: [PATCH 1/8] Added NativeBalanceGteEnforcer (#422) --- script/DeployEnvironmentSetUp.s.sol | 4 + src/enforcers/NativeBalanceGteEnforcer.sol | 103 +++++++++++++ test/enforcers/ERC20BalanceGteEnforcer.t.sol | 2 +- test/enforcers/NativeBalanceGteEnforcer.t.sol | 141 ++++++++++++++++++ 4 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 src/enforcers/NativeBalanceGteEnforcer.sol create mode 100644 test/enforcers/NativeBalanceGteEnforcer.t.sol diff --git a/script/DeployEnvironmentSetUp.s.sol b/script/DeployEnvironmentSetUp.s.sol index c5912e0..5638150 100644 --- a/script/DeployEnvironmentSetUp.s.sol +++ b/script/DeployEnvironmentSetUp.s.sol @@ -22,6 +22,7 @@ import { LimitedCallsEnforcer } from "../src/enforcers/LimitedCallsEnforcer.sol" import { NonceEnforcer } from "../src/enforcers/NonceEnforcer.sol"; import { TimestampEnforcer } from "../src/enforcers/TimestampEnforcer.sol"; import { ValueLteEnforcer } from "../src/enforcers/ValueLteEnforcer.sol"; +import { NativeBalanceGteEnforcer } from "../src/enforcers/NativeBalanceGteEnforcer.sol"; /** * @title DeployEnvironmentSetUp @@ -101,6 +102,9 @@ contract DeployEnvironmentSetUp is Script { address valueLteEnfocer = address(new ValueLteEnforcer{ salt: salt }()); console2.log("ValueLteEnforcer: %s", address(valueLteEnfocer)); + address nativeBalanceGteEnforcer = address(new NativeBalanceGteEnforcer{ salt: salt }()); + console2.log("NativeBalanceGteEnforcer: %s", address(nativeBalanceGteEnforcer)); + vm.stopBroadcast(); } } diff --git a/src/enforcers/NativeBalanceGteEnforcer.sol b/src/enforcers/NativeBalanceGteEnforcer.sol new file mode 100644 index 0000000..e599d8b --- /dev/null +++ b/src/enforcers/NativeBalanceGteEnforcer.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT AND Apache-2.0 +pragma solidity 0.8.23; + +import { CaveatEnforcer } from "./CaveatEnforcer.sol"; +import { Action } from "../utils/Types.sol"; + +/** + * @title NativeBalanceGteEnforcer + * @dev This contract enforces that a recipient's native token balance has increased by at least the specified amount + * after the action has been executed, measured between the `beforeHook` and `afterHook` calls, regardless of what the action is. + * @dev This contract does not enforce how the balance increases. It is meant to be used with additional enforcers to create + * granular permissions. + */ +contract NativeBalanceGteEnforcer is CaveatEnforcer { + ////////////////////////////// State ////////////////////////////// + + mapping(bytes32 hashKey => uint256 balance) public balanceCache; + mapping(bytes32 hashKey => bool lock) public isLocked; + + ////////////////////////////// External Methods ////////////////////////////// + + /** + * @notice Generates the key that identifies the run, produced by hashing the provided values. + * @param _caller Address of the sender calling the enforcer. + * @param _delegationHash The hash of the delegation. + * @return The hash to be used as key of the mapping. + */ + function getHashKey(address _caller, bytes32 _delegationHash) external pure returns (bytes32) { + return _getHashKey(_caller, _delegationHash); + } + + ////////////////////////////// Public Methods ////////////////////////////// + + /** + * @notice Caches the recipient's native token balance before the delegation is executed. + * @param _terms 52 packed bytes where the first 20 bytes are the recipient's address, and the next 32 bytes + * are the minimum balance increase required. + * @param _delegationHash The hash of the delegation being operated on. + */ + function beforeHook( + bytes calldata _terms, + bytes calldata, + Action calldata, + bytes32 _delegationHash, + address, + address + ) + public + override + { + bytes32 hashKey_ = _getHashKey(msg.sender, _delegationHash); + (address recipient_,) = getTermsInfo(_terms); + + require(!isLocked[hashKey_], "NativeBalanceGteEnforcer:enforcer-is-locked"); + isLocked[hashKey_] = true; + balanceCache[hashKey_] = recipient_.balance; + } + + /** + * @notice Ensures that the recipient's native token balance has increased by at least the specified amount. + * @param _terms 52 packed bytes where the first 20 bytes are the recipient's address, and the next 32 bytes + * are the minimum balance increase required. + * @param _delegationHash The hash of the delegation being operated on. + */ + function afterHook( + bytes calldata _terms, + bytes calldata, + Action calldata, + bytes32 _delegationHash, + address, + address + ) + public + override + { + (address recipient_, uint256 amount_) = getTermsInfo(_terms); + bytes32 hashKey_ = _getHashKey(msg.sender, _delegationHash); + delete isLocked[hashKey_]; + require(recipient_.balance >= balanceCache[hashKey_] + amount_, "NativeBalanceGteEnforcer:balance-not-gt"); + } + + /** + * @notice Decodes the terms used in this CaveatEnforcer. + * @param _terms 52 packed bytes where the first 20 bytes are the recipient's address, and the next 32 bytes + * specify the minimum balance increase required. + * @return recipient_ The address of the recipient who will receive the tokens. + * @return amount_ requiredIncrease_ The minimum balance increase required. + */ + function getTermsInfo(bytes calldata _terms) public pure returns (address recipient_, uint256 amount_) { + require(_terms.length == 52, "NativeBalanceGteEnforcer:invalid-terms-length"); + recipient_ = address(bytes20(_terms[:20])); + amount_ = uint256(bytes32(_terms[20:])); + } + + ////////////////////////////// Internal Methods ////////////////////////////// + + /** + * @notice Generates the key that identifies the run, produced by hashing the provided values. + */ + function _getHashKey(address _caller, bytes32 _delegationHash) private pure returns (bytes32) { + return keccak256(abi.encode(_caller, _delegationHash)); + } +} diff --git a/test/enforcers/ERC20BalanceGteEnforcer.t.sol b/test/enforcers/ERC20BalanceGteEnforcer.t.sol index 39a0d97..7776891 100644 --- a/test/enforcers/ERC20BalanceGteEnforcer.t.sol +++ b/test/enforcers/ERC20BalanceGteEnforcer.t.sol @@ -28,7 +28,7 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { delegate = address(users.bob.deleGator); dm = address(delegationManager); enforcer = new ERC20BalanceGteEnforcer(); - vm.label(address(enforcer), "Incremental ID Enforcer"); + vm.label(address(enforcer), "ERC20 BalanceGte Enforcer"); token = new BasicERC20(delegator, "TEST", "TEST", 0); vm.label(address(token), "ERC20 Test Token"); mintAction = Action({ to: address(token), value: 0, data: abi.encodeWithSelector(token.mint.selector, delegator, 100) }); diff --git a/test/enforcers/NativeBalanceGteEnforcer.t.sol b/test/enforcers/NativeBalanceGteEnforcer.t.sol new file mode 100644 index 0000000..e14b151 --- /dev/null +++ b/test/enforcers/NativeBalanceGteEnforcer.t.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: MIT AND Apache-2.0 +pragma solidity 0.8.23; + +import "../../src/utils/Types.sol"; +import { Action } from "../../src/utils/Types.sol"; +import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; +import { NativeBalanceGteEnforcer } from "../../src/enforcers/NativeBalanceGteEnforcer.sol"; +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; +import { Counter } from "../utils/Counter.t.sol"; + +contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { + ////////////////////////////// State ////////////////////////////// + NativeBalanceGteEnforcer public enforcer; + address delegator; + address delegate; + address dm; + Action noAction; + + ////////////////////// Set up ////////////////////// + + function setUp() public override { + super.setUp(); + delegator = address(users.alice.deleGator); + delegate = address(users.bob.deleGator); + dm = address(delegationManager); + enforcer = new NativeBalanceGteEnforcer(); + vm.label(address(enforcer), "NativeBalanceGte Enforcer"); + noAction = Action(address(0), 0, hex""); + } + + ////////////////////// Basic Functionality ////////////////////// + + // Validates the terms get decoded correctly + function test_decodedTheTerms() public { + bytes memory terms_ = abi.encodePacked(address(users.carol.deleGator), uint256(100)); + uint256 amount_; + address recipient_; + (recipient_, amount_) = enforcer.getTermsInfo(terms_); + assertEq(recipient_, address(address(users.carol.deleGator))); + assertEq(amount_, 100); + } + + // Validates that a balance has increased at least the expected amount + function test_allow_ifBalanceIncreases() public { + address recipient_ = delegator; + // Expect it to increase by at least 100 + bytes memory terms_ = abi.encodePacked(recipient_, uint256(100)); + + // Increase by 100 + vm.startPrank(dm); + enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + _increaseBalance(delegator, 100); + enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + + // Increase by 1000 + enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + _increaseBalance(delegator, 1000); + enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + } + + // ////////////////////// Errors ////////////////////// + + // Reverts if a balance hasn't increased by the specified amount + function test_notAllow_insufficientIncrease() public { + address recipient_ = delegator; + // Expect it to increase by at least 100 + bytes memory terms_ = abi.encodePacked(recipient_, uint256(100)); + + // Increase by 10, expect revert + vm.startPrank(dm); + enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + _increaseBalance(delegator, 10); + vm.expectRevert(bytes("NativeBalanceGteEnforcer:balance-not-gt")); + enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + } + + // Reverts if a enforcer is locked + function test_notAllow_reenterALockedEnforcer() public { + address recipient_ = delegator; + // Expect it to increase by at least 100 + bytes memory terms_ = abi.encodePacked(recipient_, uint256(100)); + bytes32 delegationHash_ = bytes32(uint256(99999999)); + + // Increase by 100 + vm.startPrank(dm); + // Locks the enforcer + enforcer.beforeHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + bytes32 hashKey_ = enforcer.getHashKey(address(delegationManager), delegationHash_); + assertTrue(enforcer.isLocked(hashKey_)); + vm.expectRevert(bytes("NativeBalanceGteEnforcer:enforcer-is-locked")); + enforcer.beforeHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + _increaseBalance(delegator, 1000); + vm.startPrank(dm); + + // Unlocks the enforcer + enforcer.afterHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + assertFalse(enforcer.isLocked(hashKey_)); + // Can be used again, and locks it again + enforcer.beforeHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + assertTrue(enforcer.isLocked(hashKey_)); + } + + // Validates the terms are well formed + function test_invalid_decodedTheTerms() public { + address recipient_ = delegator; + bytes memory terms_; + + // Too small + terms_ = abi.encodePacked(recipient_, uint8(100)); + vm.expectRevert(bytes("NativeBalanceGteEnforcer:invalid-terms-length")); + enforcer.getTermsInfo(terms_); + + // Too large + terms_ = abi.encodePacked(uint256(100), uint256(100)); + vm.expectRevert(bytes("NativeBalanceGteEnforcer:invalid-terms-length")); + enforcer.getTermsInfo(terms_); + } + + // Validates that an invalid ID reverts + function test_notAllow_expectingOverflow() public { + address recipient_ = delegator; + + // Expect balance to increase so much that the validation overflows + bytes memory terms_ = abi.encodePacked(recipient_, type(uint256).max); + vm.deal(recipient_, type(uint256).max); + vm.startPrank(dm); + enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + vm.expectRevert(); + enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + } + + function _increaseBalance(address _recipient, uint256 _amount) internal { + vm.deal(_recipient, _recipient.balance + _amount); + } + + ////////////////////// Integration ////////////////////// + + function _getEnforcer() internal view override returns (ICaveatEnforcer) { + return ICaveatEnforcer(address(enforcer)); + } +} From 69d3d3ca939b1b0a695453de7f36027e43f57b46 Mon Sep 17 00:00:00 2001 From: Dylan <13701258+dylandesrosier@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:16:26 -0400 Subject: [PATCH 2/8] Delete Unnecessary Scope (#427) --- src/DelegationManager.sol | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/DelegationManager.sol b/src/DelegationManager.sol index f7b72b5..078e793 100644 --- a/src/DelegationManager.sol +++ b/src/DelegationManager.sol @@ -213,17 +213,15 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 } } - { - // beforeHook (leaf to root) - for (uint256 i; i < delegations_.length; ++i) { - Caveat[] memory caveats_ = delegations_[i].caveats; - bytes32 delegationHash_ = delegationHashes_[i]; - address delegator_ = delegations_[i].delegator; - uint256 caveatsLength_ = caveats_.length; - for (uint256 j; j < caveatsLength_; ++j) { - ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[j].enforcer); - enforcer_.beforeHook(caveats_[j].terms, caveats_[j].args, _action, delegationHash_, delegator_, msg.sender); - } + // beforeHook (leaf to root) + for (uint256 i; i < delegations_.length; ++i) { + Caveat[] memory caveats_ = delegations_[i].caveats; + bytes32 delegationHash_ = delegationHashes_[i]; + address delegator_ = delegations_[i].delegator; + uint256 caveatsLength_ = caveats_.length; + for (uint256 j; j < caveatsLength_; ++j) { + ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[j].enforcer); + enforcer_.beforeHook(caveats_[j].terms, caveats_[j].args, _action, delegationHash_, delegator_, msg.sender); } } From 7e998b81a3db1a2fac3425cbcd304f2642587520 Mon Sep 17 00:00:00 2001 From: Hanzel Anchia Mena <33629234+hanzel98@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:31:46 -0600 Subject: [PATCH 3/8] Added Redeemer Enforcer (#425) --- src/enforcers/RedeemerEnforcer.sol | 56 +++++++++++++++++ test/enforcers/RedeemerEnforcer.t.sol | 87 +++++++++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 src/enforcers/RedeemerEnforcer.sol create mode 100644 test/enforcers/RedeemerEnforcer.t.sol diff --git a/src/enforcers/RedeemerEnforcer.sol b/src/enforcers/RedeemerEnforcer.sol new file mode 100644 index 0000000..aea25d9 --- /dev/null +++ b/src/enforcers/RedeemerEnforcer.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { CaveatEnforcer } from "./CaveatEnforcer.sol"; +import { Action } from "../utils/Types.sol"; + +/** + * @title RedeemerEnforcer + * @dev This contract restricts the addresses that can redeem delegations. + * Specifically designed for smart contracts or EOAs lacking delegation support. + * Note: DeleGator accounts with delegation functionalities may bypass these restrictions by delegating to other addresses. + */ +contract RedeemerEnforcer is CaveatEnforcer { + ////////////////////////////// Public Methods ////////////////////////////// + + /** + * @notice Allows the delegator to limit which addresses can redeem the delegation. + * @param _terms Encoded 20-byte addresses of the allowed redeemers. + * @param _redeemer The address attempting to redeem the delegation. + */ + function beforeHook( + bytes calldata _terms, + bytes calldata, + Action calldata, + bytes32, + address, + address _redeemer + ) + public + pure + override + { + address[] memory allowedRedeemers_ = getTermsInfo(_terms); + uint256 allowedRedeemersLength_ = allowedRedeemers_.length; + for (uint256 i = 0; i < allowedRedeemersLength_; ++i) { + if (_redeemer == allowedRedeemers_[i]) return; + } + revert("RedeemerEnforcer:unauthorized-redeemer"); + } + + /** + * @notice Decodes the terms used in this CaveatEnforcer. + * @param _terms Encoded 20-byte addresses of the allowed redeemers. + * @return allowedRedeemers_ Array containing the allowed redeemer addresses. + */ + function getTermsInfo(bytes calldata _terms) public pure returns (address[] memory allowedRedeemers_) { + uint256 j = 0; + uint256 termsLength_ = _terms.length; + require(termsLength_ > 0 && termsLength_ % 20 == 0, "RedeemerEnforcer:invalid-terms-length"); + allowedRedeemers_ = new address[](termsLength_ / 20); + for (uint256 i = 0; i < termsLength_; i += 20) { + allowedRedeemers_[j] = address(bytes20(_terms[i:i + 20])); + j++; + } + } +} diff --git a/test/enforcers/RedeemerEnforcer.t.sol b/test/enforcers/RedeemerEnforcer.t.sol new file mode 100644 index 0000000..396c8eb --- /dev/null +++ b/test/enforcers/RedeemerEnforcer.t.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { Action } from "../../src/utils/Types.sol"; +import { Counter } from "../utils/Counter.t.sol"; +import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; +import { RedeemerEnforcer } from "../../src/enforcers/RedeemerEnforcer.sol"; +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; + +contract RedeemerEnforcerTest is CaveatEnforcerBaseTest { + ////////////////////////////// State ////////////////////////////// + RedeemerEnforcer public redeemerEnforcer; + + ////////////////////// Set up ////////////////////// + + function setUp() public override { + super.setUp(); + redeemerEnforcer = new RedeemerEnforcer(); + vm.label(address(redeemerEnforcer), "Redeemer Enforcer"); + } + + ////////////////////// Valid cases ////////////////////// + + // should SUCCEED to get terms info when passing valid terms + function test_decodeTermsInfo() public { + bytes memory terms_ = abi.encodePacked(address(users.alice.deleGator), address(users.bob.deleGator)); + address[] memory allowedRedeemers_ = redeemerEnforcer.getTermsInfo(terms_); + assertEq(allowedRedeemers_[0], address(users.alice.deleGator)); + assertEq(allowedRedeemers_[1], address(users.bob.deleGator)); + } + + // should pass if called from a single valid redeemer + function test_validSingleRedeemerCanExecute() public { + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + bytes memory terms_ = abi.encodePacked(address(users.bob.deleGator)); + vm.prank(address(delegationManager)); + redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.bob.deleGator)); + } + + // should pass if called from multiple valid redeemers + function test_validMultipleRedeemersCanExecute() public { + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + bytes memory terms_ = abi.encodePacked(address(users.alice.deleGator), address(users.bob.deleGator)); + vm.startPrank(address(delegationManager)); + redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.alice.deleGator)); + redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.bob.deleGator)); + } + + ////////////////////// Invalid cases ////////////////////// + + // should FAIL to get terms info when passing an invalid terms length + function test_getTermsInfoFailsForInvalidLength() public { + vm.expectRevert("RedeemerEnforcer:invalid-terms-length"); + redeemerEnforcer.getTermsInfo(bytes("1")); + } + + // should revert if called from an invalid redeemer + function test_revertWithInvalidRedeemer() public { + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + bytes memory terms_ = abi.encodePacked(address(users.bob.deleGator)); + vm.prank(address(delegationManager)); + // Dave is not a valid redeemer + vm.expectRevert("RedeemerEnforcer:unauthorized-redeemer"); + redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.dave.deleGator)); + } + + // should revert with invalid terms length + function test_revertWithInvalidTerms() public { + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + bytes memory invalidTerms_ = abi.encodePacked(uint8(1)); + vm.prank(address(delegationManager)); + vm.expectRevert("RedeemerEnforcer:invalid-terms-length"); + redeemerEnforcer.beforeHook(invalidTerms_, hex"", action_, keccak256(""), address(0), address(users.bob.deleGator)); + } + + function _getEnforcer() internal view override returns (ICaveatEnforcer) { + return ICaveatEnforcer(address(redeemerEnforcer)); + } +} From 751a039a070ae6ce5eaf24f768db49c22b6ee9c1 Mon Sep 17 00:00:00 2001 From: Hanzel Anchia Mena <33629234+hanzel98@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:32:21 -0600 Subject: [PATCH 4/8] Deleted Onchain Delegations (#420) --- .gas-snapshot | 743 ++++---- documents/DelegationManager.md | 17 +- src/DeleGatorCore.sol | 18 - src/DelegationManager.sol | 69 +- src/interfaces/IDeleGatorCoreFull.sol | 4 - src/interfaces/IDelegationManager.sol | 14 +- {test => src}/utils/SimpleFactory.sol | 0 test/DeleGatorTestSuite.t.sol | 1540 +++++------------ test/HybridDeleGatorTest.t.sol | 49 - test/InviteTest.t.sol | 2 +- test/MultiSigDeleGatorTest.t.sol | 42 +- test/enforcers/AllowedCalldataEnforcer.t.sol | 8 +- test/enforcers/AllowedMethodsEnforcer.t.sol | 8 +- test/enforcers/AllowedTargetsEnforcer.t.sol | 8 +- test/enforcers/BlockNumberEnforcer.t.sol | 3 +- test/enforcers/DeployedEnforcer.t.sol | 4 +- .../ERC20TransferAmountEnforcer.t.sol | 4 +- test/enforcers/IdEnforcer.t.sol | 4 +- test/enforcers/LimitedCallsEnforcer.t.sol | 3 +- test/enforcers/PasswordEnforcer.t.sol | 38 +- test/enforcers/TimestampEnforcer.t.sol | 4 +- test/enforcers/ValueLteEnforcer.t.sol | 2 +- test/utils/BaseTest.t.sol | 2 +- 23 files changed, 886 insertions(+), 1700 deletions(-) rename {test => src}/utils/SimpleFactory.sol (100%) diff --git a/.gas-snapshot b/.gas-snapshot index 37d4175..c661783 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,395 +1,348 @@ -AllowedCalldataEnforcerTest:test_failsWithInvalidTermsLength() (gas: 22806) -AllowedCalldataEnforcerTest:test_methodCanBeCalledWithSpecificMetadata() (gas: 25539) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualDynamicArrayParam() (gas: 32959) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualDynamicStringParam() (gas: 31833) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualParam() (gas: 21784) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualParamIntegration() (gas: 667292) -AllowedCalldataEnforcerTest:test_singleMethodCanNotBeCalledWithNonEqualParamIntegration() (gas: 480123) -AllowedCalldataEnforcerTest:test_singleMethodCanNotCalledWithInvalidTermsSize() (gas: 20232) -AllowedCalldataEnforcerTest:test_singleMethodCanNotCalledWithNonEqualParam() (gas: 22616) -AllowedMethodsEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 12141) -AllowedMethodsEnforcerTest:test_methodCanBeSingleMethodIntegration() (gas: 651654) -AllowedMethodsEnforcerTest:test_multiMethodCanBeCalled() (gas: 21595) -AllowedMethodsEnforcerTest:test_notAllow_invalidActionLength() (gas: 18051) -AllowedMethodsEnforcerTest:test_onlyApprovedMethodsCanBeCalled() (gas: 22542) -AllowedMethodsEnforcerTest:test_onlyApprovedMethodsCanBeCalledIntegration() (gas: 478827) -AllowedMethodsEnforcerTest:test_singleMethodCanBeCalled() (gas: 18951) -AllowedTargetsEnforcerTest:testFToken1() (gas: 2761) -AllowedTargetsEnforcerTest:testFToken2() (gas: 2803) -AllowedTargetsEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 12183) -AllowedTargetsEnforcerTest:test_multiTargetCanBeCalled() (gas: 25981) -AllowedTargetsEnforcerTest:test_multiTargetCanBeCalledIntegration() (gas: 974411) -AllowedTargetsEnforcerTest:test_onlyApprovedMethodsCanBeCalledIntegration() (gas: 489354) -AllowedTargetsEnforcerTest:test_onlyApprovedTargetsCanBeCalled() (gas: 28925) -AllowedTargetsEnforcerTest:test_singleTargetCanBeCalled() (gas: 18735) -BlockNumberEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 9755) -BlockNumberEnforcerTest:test_methodCanBeCalledAfterBlockNumber() (gas: 18148) -BlockNumberEnforcerTest:test_methodCanBeCalledAfterBlockNumberIntegration() (gas: 632477) -BlockNumberEnforcerTest:test_methodCanBeCalledBeforeBlockNumber() (gas: 17781) -BlockNumberEnforcerTest:test_methodCanBeCalledInsideBlockNumberRange() (gas: 18414) -BlockNumberEnforcerTest:test_methodFailsIfCalledAfterBlockNumber() (gas: 19076) -BlockNumberEnforcerTest:test_methodFailsIfCalledAfterBlockNumberRange() (gas: 19488) -BlockNumberEnforcerTest:test_methodFailsIfCalledBeforeBlockNumber() (gas: 18567) -BlockNumberEnforcerTest:test_methodFailsIfCalledBeforeBlockNumberRange() (gas: 18763) -CounterfactualAssetsTest:test_allow_createNftAndDelegateWithCaveatsAndRedelegate_offchain() (gas: 5154246) -CounterfactualAssetsTest:test_allow_createNftAndDelegateWithCaveats_offchain() (gas: 5080861) -CounterfactualAssetsTest:test_allow_createNftAndDelegate_offchain() (gas: 5027113) -DelegationManagerTest:test_allow_anyDelegateReads() (gas: 5921) -DelegationManagerTest:test_allow_contractNameReads() (gas: 7921) -DelegationManagerTest:test_allow_contractVersionReads() (gas: 8029) -DelegationManagerTest:test_allow_domainHashReads() (gas: 11049) -DelegationManagerTest:test_allow_domainHashReadsWhenChainIdChanges() (gas: 14836) -DelegationManagerTest:test_allow_domainVersionReads() (gas: 7875) -DelegationManagerTest:test_allow_getDelegationHash() (gas: 19919) -DelegationManagerTest:test_allow_rootAuthorityReads() (gas: 5837) -DelegationManagerTest:test_notAllow_crossDelegationManagerReplays() (gas: 3259077) -DelegationManagerTest:test_notAllow_invalidSignatureReturns() (gas: 211072) -DelegationManagerTest:test_notAllow_invalidSignatureReverts() (gas: 245145) -DelegationManagerTest:test_ownership_transferAndAcceptOwnership() (gas: 38437) -DelegationManagerTest:test_pausability_allowsOwnerToPause() (gas: 41993) -DelegationManagerTest:test_pausability_allowsOwnerToPauseRedemptions() (gas: 40129) -DelegationManagerTest:test_pausability_allowsOwnerToUnpause() (gas: 31656) -DelegationManagerTest:test_pausability_failsToPauseIfNotOwner() (gas: 19272) -DelegationManagerTest:test_pausability_failsToPauseWhenActivePause() (gas: 38830) -DelegationManagerTest:test_pausability_failsToPauseWhenActiveUnpause() (gas: 16132) -DelegationManagerTest:test_pausability_failsToUnpauseIfNotOwner() (gas: 43849) -DelegationManagerTest:test_pausability_validateInitialPauseState() (gas: 2983890) -DeployedEnforcerTest:test_deploysIfNonExistent() (gas: 287197) -DeployedEnforcerTest:test_deploysIfNonExistentAndAllowsToUseItIntegration() (gas: 798500) -DeployedEnforcerTest:test_doesNotDeployIfExistent() (gas: 180998) -DeployedEnforcerTest:test_event_factoryDeployedEvent() (gas: 155820) -DeployedEnforcerTest:test_revertIfContractIsEmpty() (gas: 66940) -DeployedEnforcerTest:test_revertIfFactoryAddressIsInvalid() (gas: 705668) -DeployedEnforcerTest:test_revertIfPredictedAddressDoesNotMatch() (gas: 174875) -DeployedEnforcerTest:test_revertIfTermsLengthIsInvalid() (gas: 19577) -DeployedEnforcerTest:test_revertsIfBytecodeDoesntExist() (gas: 1024174696) -DeployedEnforcerTest:test_shouldReadFactoryAddress() (gas: 7955) -ERC20BalanceGteEnforcerTest:test_allow_ifBalanceIncreases() (gas: 150972) -ERC20BalanceGteEnforcerTest:test_decodedTheTerms() (gas: 10835) -ERC20BalanceGteEnforcerTest:test_invalid_decodedTheTerms() (gas: 17801) -ERC20BalanceGteEnforcerTest:test_invalid_tokenAddress() (gas: 56499) -ERC20BalanceGteEnforcerTest:test_notAllow_expectingOverflow() (gas: 80199) -ERC20BalanceGteEnforcerTest:test_notAllow_insufficientIncrease() (gas: 107025) -ERC20BalanceGteEnforcerTest:test_notAllow_reenterALockedEnforcer() (gas: 172966) -ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidContract() (gas: 38087) -ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidMethod() (gas: 36682) -ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidTermsLength() (gas: 34745) -ERC20TransferAmountEnforcerTest:test_notAllow_invalidActionLength() (gas: 35318) -ERC20TransferAmountEnforcerTest:test_transferFailsAboveAllowance() (gas: 839655) -ERC20TransferAmountEnforcerTest:test_transferFailsIfCalledAboveAllowance() (gas: 58020) -ERC20TransferAmountEnforcerTest:test_transferSucceedsIfCalledBelowAllowance() (gas: 63660) -EncoderLibTest:test_ShouldEncodeAnArrayOfCaveats() (gas: 14116) -EncoderLibTest:test_ShouldEncodeOneCaveat() (gas: 6495) -EncoderLibTest:test_shouldEncodeOneDelegation() (gas: 10626) -HybridDeleGator_Test:test_allow_addKey() (gas: 494680) -HybridDeleGator_Test:test_allow_erc173InterfaceId() (gas: 14416) -HybridDeleGator_Test:test_allow_removeKey() (gas: 732973) -HybridDeleGator_Test:test_allow_replaceEOAWithEOA() (gas: 201287) -HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256() (gas: 306400) -HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256WithOffchainDelegation() (gas: 774890) -HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256WithOnchainDelegation() (gas: 944226) -HybridDeleGator_Test:test_allow_replaceEOAWithP256() (gas: 297439) -HybridDeleGator_Test:test_allow_signatureWithEOA() (gas: 43120) -HybridDeleGator_Test:test_allow_signatureWithP256() (gas: 250607) -HybridDeleGator_Test:test_allow_signingWithWebAuthn() (gas: 508409) -HybridDeleGator_Test:test_allow_upgradingHybridDeleGator() (gas: 523442) -HybridDeleGator_Test:test_error_replacedSignersInputsMismatch() (gas: 47243) -HybridDeleGator_Test:test_error_replacedSignersToEmpty() (gas: 17362) -HybridDeleGator_Test:test_events_replacedSigners() (gas: 120022) -HybridDeleGator_Test:test_fails_signingWithWebAuthnWithInvalidType() (gas: 241562) -HybridDeleGator_Test:test_initialize_multipleP256OneEOA() (gas: 728348) -HybridDeleGator_Test:test_initialize_multipleP256ZeroEOA() (gas: 706117) -HybridDeleGator_Test:test_initialize_zeroP256OneEOA() (gas: 168585) -HybridDeleGator_Test:test_keyAdded_addKey() (gas: 495175) -HybridDeleGator_Test:test_keyAdded_initialize() (gas: 276464) -HybridDeleGator_Test:test_keyRemoved_removeKey() (gas: 732534) -HybridDeleGator_Test:test_notAllow_addKeyNotOnCurve() (gas: 19496) -HybridDeleGator_Test:test_notAllow_addingAnEmptyKey() (gas: 16635) -HybridDeleGator_Test:test_notAllow_addingExistingKey() (gas: 26432) -HybridDeleGator_Test:test_notAllow_invalidKeyOnDeploy() (gas: 104005) -HybridDeleGator_Test:test_notAllow_invalidSignatureLength() (gas: 24650) -HybridDeleGator_Test:test_notAllow_removingLastKeyViaEOA() (gas: 31448) -HybridDeleGator_Test:test_notAllow_removingLastKeyViaP256() (gas: 28302) -HybridDeleGator_Test:test_notAllow_removingNonExistantKey() (gas: 23498) -HybridDeleGator_Test:test_notAllow_renounceOwnership_Direct() (gas: 20326) -HybridDeleGator_Test:test_notAllow_transferOwnership_directNonOwner() (gas: 17729) -HybridDeleGator_Test:test_notAllow_transferOwnership_directOwner() (gas: 19706) -HybridDeleGator_Test:test_reinitialize_clearsAndSetSigners() (gas: 197577) -HybridDeleGator_Test:test_reinitialize_keepAndSetSigners() (gas: 212787) -HybridDeleGator_Test:test_removeP256KeyAndRearrangeStoredKeyIdHashes() (gas: 179883) -HybridDeleGator_Test:test_return_KeyIdHashes() (gas: 496239) -HybridDeleGator_Test:test_upgradeMultipleTimes() (gas: 597086) -HybridDeleGator_Test:test_upgradeWithoutStorageCleanup() (gas: 488197) -HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 355578) -HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 177648) -HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOnchainDelegationToDeleGators() (gas: 696220) -HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOnchainDelegationToEoa() (gas: 532503) -HybridDeleGator_TestSuite_EOA_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 295543) -HybridDeleGator_TestSuite_EOA_Test:test_allow_deleGatorInvokeOnchainDelegation() (gas: 464863) -HybridDeleGator_TestSuite_EOA_Test:test_allow_disableOffchainDelegation() (gas: 609459) -HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 120208) -HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaInvokeOnchainDelegation() (gas: 303112) -HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 159820) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getDeposit() (gas: 16946) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getEntryPoint() (gas: 13363) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getNonce() (gas: 17515) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getNonceWithKey() (gas: 17865) -HybridDeleGator_TestSuite_EOA_Test:test_allow_invokeCombinedDelegationChain() (gas: 526905) -HybridDeleGator_TestSuite_EOA_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 350726) -HybridDeleGator_TestSuite_EOA_Test:test_allow_invokeOnchainDelegationWithCaveats() (gas: 541406) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionCombination_UserOp() (gas: 345515) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 355277) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionDelegationClaim_Onchain_UserOp() (gas: 514293) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiAction_UserOp() (gas: 229417) -HybridDeleGator_TestSuite_EOA_Test:test_allow_offchainOpenDelegation() (gas: 383284) -HybridDeleGator_TestSuite_EOA_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 206716) -HybridDeleGator_TestSuite_EOA_Test:test_allow_onchainOpenDelegation() (gas: 568147) -HybridDeleGator_TestSuite_EOA_Test:test_allow_onchainOpenDelegationRedelegation() (gas: 588268) -HybridDeleGator_TestSuite_EOA_Test:test_allow_receiveNativeToken() (gas: 17890) -HybridDeleGator_TestSuite_EOA_Test:test_allow_resetDisabledDelegation() (gas: 459605) -HybridDeleGator_TestSuite_EOA_Test:test_allow_storeOnchainDelegation() (gas: 242935) -HybridDeleGator_TestSuite_EOA_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 333855) -HybridDeleGator_TestSuite_EOA_Test:test_allow_updatingOnchainDelegationDisabledStateWithStruct() (gas: 459525) -HybridDeleGator_TestSuite_EOA_Test:test_allow_withdrawDeposit() (gas: 299714) -HybridDeleGator_TestSuite_EOA_Test:test_emit_executedActionEvent() (gas: 75315) -HybridDeleGator_TestSuite_EOA_Test:test_emit_sentPrefund() (gas: 77389) -HybridDeleGator_TestSuite_EOA_Test:test_erc165_supportsInterface() (gas: 21974) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidAuthority() (gas: 661059) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidDelegate() (gas: 435881) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidDelegator() (gas: 214334) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidRootAuthority() (gas: 264276) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidSignature() (gas: 268189) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidSigner() (gas: 267866) -HybridDeleGator_TestSuite_EOA_Test:test_error_NoDelegationsProvided() (gas: 425587) -HybridDeleGator_TestSuite_EOA_Test:test_event_Deposited() (gas: 209795) -HybridDeleGator_TestSuite_EOA_Test:test_event_storeDelegation() (gas: 239350) -HybridDeleGator_TestSuite_EOA_Test:test_executesFirstRootAuthorityFound() (gas: 308469) -HybridDeleGator_TestSuite_EOA_Test:test_executionRevertsWithoutReason() (gas: 33370) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_alreadyExistingDelegation() (gas: 342392) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 86155) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 89096) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 327670) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 214399) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_delegationWithoutSignature() (gas: 42116) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 476910) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_disablingInvalidDelegation() (gas: 214511) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_emptyAction_UserOp() (gas: 190853) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 344423) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 89686) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidEntryPoint() (gas: 5683108) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidRedeemDelegationData() (gas: 255747) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidUserOpSignature() (gas: 148688) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 243580) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invokeOnchainDelegationToAnotherUser() (gas: 428504) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_multiActionUserOp() (gas: 217094) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_nonceReuse() (gas: 240656) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_notDelegationManager() (gas: 17406) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_notEntryPoint() (gas: 17408) -HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 990394) -HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 601105) -HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOnchainDelegationToDeleGators() (gas: 1327318) -HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOnchainDelegationToEoa() (gas: 964341) -HybridDeleGator_TestSuite_P256_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 714784) -HybridDeleGator_TestSuite_P256_Test:test_allow_deleGatorInvokeOnchainDelegation() (gas: 889953) -HybridDeleGator_TestSuite_P256_Test:test_allow_disableOffchainDelegation() (gas: 1647104) -HybridDeleGator_TestSuite_P256_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 325793) -HybridDeleGator_TestSuite_P256_Test:test_allow_eoaInvokeOnchainDelegation() (gas: 519648) -HybridDeleGator_TestSuite_P256_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 365405) -HybridDeleGator_TestSuite_P256_Test:test_allow_getDeposit() (gas: 16946) -HybridDeleGator_TestSuite_P256_Test:test_allow_getEntryPoint() (gas: 13363) -HybridDeleGator_TestSuite_P256_Test:test_allow_getNonce() (gas: 17515) -HybridDeleGator_TestSuite_P256_Test:test_allow_getNonceWithKey() (gas: 17865) -HybridDeleGator_TestSuite_P256_Test:test_allow_invokeCombinedDelegationChain() (gas: 1157169) -HybridDeleGator_TestSuite_P256_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 773343) -HybridDeleGator_TestSuite_P256_Test:test_allow_invokeOnchainDelegationWithCaveats() (gas: 973484) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionCombination_UserOp() (gas: 771321) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 985819) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionDelegationClaim_Onchain_UserOp() (gas: 941092) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiAction_UserOp() (gas: 434220) -HybridDeleGator_TestSuite_P256_Test:test_allow_offchainOpenDelegation() (gas: 1002124) -HybridDeleGator_TestSuite_P256_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 624116) -HybridDeleGator_TestSuite_P256_Test:test_allow_onchainOpenDelegation() (gas: 993720) -HybridDeleGator_TestSuite_P256_Test:test_allow_onchainOpenDelegationRedelegation() (gas: 1013782) -HybridDeleGator_TestSuite_P256_Test:test_allow_receiveNativeToken() (gas: 17890) -HybridDeleGator_TestSuite_P256_Test:test_allow_resetDisabledDelegation() (gas: 1088252) -HybridDeleGator_TestSuite_P256_Test:test_allow_storeOnchainDelegation() (gas: 459475) -HybridDeleGator_TestSuite_P256_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 754627) -HybridDeleGator_TestSuite_P256_Test:test_allow_updatingOnchainDelegationDisabledStateWithStruct() (gas: 1103305) -HybridDeleGator_TestSuite_P256_Test:test_allow_withdrawDeposit() (gas: 718584) -HybridDeleGator_TestSuite_P256_Test:test_emit_executedActionEvent() (gas: 75315) -HybridDeleGator_TestSuite_P256_Test:test_emit_sentPrefund() (gas: 77389) -HybridDeleGator_TestSuite_P256_Test:test_erc165_supportsInterface() (gas: 21974) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidAuthority() (gas: 1302083) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidDelegate() (gas: 858882) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidDelegator() (gas: 430030) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidRootAuthority() (gas: 477650) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidSignature() (gas: 485631) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidSigner() (gas: 485308) -HybridDeleGator_TestSuite_P256_Test:test_error_NoDelegationsProvided() (gas: 847723) -HybridDeleGator_TestSuite_P256_Test:test_event_Deposited() (gas: 420427) -HybridDeleGator_TestSuite_P256_Test:test_event_storeDelegation() (gas: 453994) -HybridDeleGator_TestSuite_P256_Test:test_executesFirstRootAuthorityFound() (gas: 947294) -HybridDeleGator_TestSuite_P256_Test:test_executionRevertsWithoutReason() (gas: 33370) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_alreadyExistingDelegation() (gas: 773922) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 89068) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 92010) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 968130) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 426933) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_delegationWithoutSignature() (gas: 42116) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 1114803) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_disablingInvalidDelegation() (gas: 429999) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_emptyAction_UserOp() (gas: 405918) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 770045) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 92804) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidEntryPoint() (gas: 5689142) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidRedeemDelegationData() (gas: 472286) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidUserOpSignature() (gas: 149804) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 463030) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invokeOnchainDelegationToAnotherUser() (gas: 851505) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_multiActionUserOp() (gas: 429628) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_nonceReuse() (gas: 655989) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_notDelegationManager() (gas: 17406) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_notEntryPoint() (gas: 17408) -IdEnforcerEnforcerTest:testFToken1() (gas: 2805) -IdEnforcerEnforcerTest:test_blocksDelegationWithRepeatedNonce() (gas: 56530) -IdEnforcerEnforcerTest:test_decodedTheTerms() (gas: 7071) -IdEnforcerEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 17484) -IdEnforcerEnforcerTest:test_methodFailsIfNonceAlreadyUsed() (gas: 655300) -InviteTest:test_createADeleGatorForBobAndDelegate() (gas: 640568) -InviteTest:test_createADeleGatorForBobAndSend() (gas: 483624) -LimitedCallsEnforcerTest:test_methodCanBeCalledBelowLimitNumber() (gas: 60253) -LimitedCallsEnforcerTest:test_methodFailsAboveLimitIntegration() (gas: 664291) -LimitedCallsEnforcerTest:test_methodFailsIfCalledAboveLimitNumber() (gas: 61583) -LimitedCallsEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 17550) -MultiSigDeleGatorTest:test_DelegationManagerSetEvent() (gas: 4875423) -MultiSigDeleGatorTest:test_ImplementationUsesMaxThreshold() (gas: 7961) -MultiSigDeleGatorTest:test_InitializedImplementationEvent() (gas: 4875332) -MultiSigDeleGatorTest:test_InitializedSignersEvents() (gas: 351893) -MultiSigDeleGatorTest:test_ReinitializedSignersEvents() (gas: 145845) -MultiSigDeleGatorTest:test_allow_addSigner() (gas: 85585) -MultiSigDeleGatorTest:test_allow_deploySCAWithInitCode() (gas: 466035) -MultiSigDeleGatorTest:test_allow_getMaxSigners() (gas: 10841) -MultiSigDeleGatorTest:test_allow_getSignersCount() (gas: 13120) -MultiSigDeleGatorTest:test_allow_invokeOffchainDelegationWithMultipleSigners() (gas: 330143) -MultiSigDeleGatorTest:test_allow_invokeOnchainDelegationWithMultipleSigners() (gas: 489010) -MultiSigDeleGatorTest:test_allow_removeSigner() (gas: 232930) -MultiSigDeleGatorTest:test_allow_replaceSigner() (gas: 237682) -MultiSigDeleGatorTest:test_allow_updateMultiSigParameters_base() (gas: 587143) -MultiSigDeleGatorTest:test_allow_updatingThreshold() (gas: 84460) -MultiSigDeleGatorTest:test_error_Init_AlreadyASigner() (gas: 168435) -MultiSigDeleGatorTest:test_error_Init_InvalidSignerAddress() (gas: 98333) -MultiSigDeleGatorTest:test_error_Init_InvalidSignersLength() (gas: 301249) -MultiSigDeleGatorTest:test_error_Init_InvalidThreshold() (gas: 188429) -MultiSigDeleGatorTest:test_error_Init_thresholdGreaterThanSigners() (gas: 131752) -MultiSigDeleGatorTest:test_error_updateSigParamatersAlreadyASigner() (gas: 74645) -MultiSigDeleGatorTest:test_error_updateSigParamatersContractNewSigner() (gas: 26709) -MultiSigDeleGatorTest:test_error_updateSigParamatersZeroNewSigner() (gas: 21964) -MultiSigDeleGatorTest:test_error_updateSigParametersInvalidThreshold() (gas: 18741) -MultiSigDeleGatorTest:test_notAllow_addSigner() (gas: 1629243) -MultiSigDeleGatorTest:test_notAllow_invalidSignatureLength() (gas: 173175) -MultiSigDeleGatorTest:test_notAllow_invalidSigners() (gas: 189597) -MultiSigDeleGatorTest:test_notAllow_removeSigner() (gas: 116529) -MultiSigDeleGatorTest:test_notAllow_replaceSigner() (gas: 61732) -MultiSigDeleGatorTest:test_notAllow_signerReuse() (gas: 175049) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_access() (gas: 42297) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_maxNumberOfSigners() (gas: 47188) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_threshold() (gas: 35539) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_thresholdKeepingSigners() (gas: 29645) -MultiSigDeleGatorTest:test_notAllow_updatingThreshold() (gas: 90063) -MultiSigDeleGatorTest:test_reinitialize_clearsAndSetSigners() (gas: 134181) -MultiSigDeleGatorTest:test_reinitialize_keepAndSetSigners() (gas: 152132) -MultiSigDeleGatorTest:test_return_ifAnAddressIsAValidSigner() (gas: 22702) -MultiSigDeleGatorTest:test_unauthorizedReinitializeCall() (gas: 27056) -MultiSig_TestSuite_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 373832) -MultiSig_TestSuite_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 189749) -MultiSig_TestSuite_Test:test_allow_chainOfOnchainDelegationToDeleGators() (gas: 714476) -MultiSig_TestSuite_Test:test_allow_chainOfOnchainDelegationToEoa() (gas: 544605) -MultiSig_TestSuite_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 307734) -MultiSig_TestSuite_Test:test_allow_deleGatorInvokeOnchainDelegation() (gas: 477054) -MultiSig_TestSuite_Test:test_allow_disableOffchainDelegation() (gas: 631667) -MultiSig_TestSuite_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 126247) -MultiSig_TestSuite_Test:test_allow_eoaInvokeOnchainDelegation() (gas: 309151) -MultiSig_TestSuite_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 165860) -MultiSig_TestSuite_Test:test_allow_getDeposit() (gas: 16968) -MultiSig_TestSuite_Test:test_allow_getEntryPoint() (gas: 13385) -MultiSig_TestSuite_Test:test_allow_getNonce() (gas: 17515) -MultiSig_TestSuite_Test:test_allow_getNonceWithKey() (gas: 17821) -MultiSig_TestSuite_Test:test_allow_invokeCombinedDelegationChain() (gas: 545161) -MultiSig_TestSuite_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 362917) -MultiSig_TestSuite_Test:test_allow_invokeOnchainDelegationWithCaveats() (gas: 553599) -MultiSig_TestSuite_Test:test_allow_multiActionCombination_UserOp() (gas: 357663) -MultiSig_TestSuite_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 369333) -MultiSig_TestSuite_Test:test_allow_multiActionDelegationClaim_Onchain_UserOp() (gas: 526509) -MultiSig_TestSuite_Test:test_allow_multiAction_UserOp() (gas: 235434) -MultiSig_TestSuite_Test:test_allow_offchainOpenDelegation() (gas: 397294) -MultiSig_TestSuite_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 218817) -MultiSig_TestSuite_Test:test_allow_onchainOpenDelegation() (gas: 580317) -MultiSig_TestSuite_Test:test_allow_onchainOpenDelegationRedelegation() (gas: 600371) -MultiSig_TestSuite_Test:test_allow_receiveNativeToken() (gas: 17890) -MultiSig_TestSuite_Test:test_allow_resetDisabledDelegation() (gas: 473991) -MultiSig_TestSuite_Test:test_allow_storeOnchainDelegation() (gas: 249018) -MultiSig_TestSuite_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 344221) -MultiSig_TestSuite_Test:test_allow_updatingOnchainDelegationDisabledStateWithStruct() (gas: 473956) -MultiSig_TestSuite_Test:test_allow_withdrawDeposit() (gas: 309795) -MultiSig_TestSuite_Test:test_emit_executedActionEvent() (gas: 75271) -MultiSig_TestSuite_Test:test_emit_sentPrefund() (gas: 80123) -MultiSig_TestSuite_Test:test_erc165_supportsInterface() (gas: 21674) -MultiSig_TestSuite_Test:test_error_InvalidAuthority() (gas: 679338) -MultiSig_TestSuite_Test:test_error_InvalidDelegate() (gas: 448095) -MultiSig_TestSuite_Test:test_error_InvalidDelegator() (gas: 220418) -MultiSig_TestSuite_Test:test_error_InvalidRootAuthority() (gas: 270337) -MultiSig_TestSuite_Test:test_error_InvalidSignature() (gas: 280239) -MultiSig_TestSuite_Test:test_error_InvalidSigner() (gas: 279916) -MultiSig_TestSuite_Test:test_error_NoDelegationsProvided() (gas: 437800) -MultiSig_TestSuite_Test:test_event_Deposited() (gas: 215812) -MultiSig_TestSuite_Test:test_event_storeDelegation() (gas: 245433) -MultiSig_TestSuite_Test:test_executesFirstRootAuthorityFound() (gas: 326745) -MultiSig_TestSuite_Test:test_executionRevertsWithoutReason() (gas: 33348) -MultiSig_TestSuite_Test:test_notAllow_alreadyExistingDelegation() (gas: 352538) -MultiSig_TestSuite_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 88375) -MultiSig_TestSuite_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 91317) -MultiSig_TestSuite_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 345947) -MultiSig_TestSuite_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 220527) -MultiSig_TestSuite_Test:test_notAllow_delegationWithoutSignature() (gas: 42205) -MultiSig_TestSuite_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 491164) -MultiSig_TestSuite_Test:test_notAllow_disablingInvalidDelegation() (gas: 220551) -MultiSig_TestSuite_Test:test_notAllow_emptyAction_UserOp() (gas: 196870) -MultiSig_TestSuite_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 354613) -MultiSig_TestSuite_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 91906) -MultiSig_TestSuite_Test:test_notAllow_invalidEntryPoint() (gas: 5687534) -MultiSig_TestSuite_Test:test_notAllow_invalidRedeemDelegationData() (gas: 261808) -MultiSig_TestSuite_Test:test_notAllow_invalidUserOpSignature() (gas: 154586) -MultiSig_TestSuite_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 251952) -MultiSig_TestSuite_Test:test_notAllow_invokeOnchainDelegationToAnotherUser() (gas: 440717) -MultiSig_TestSuite_Test:test_notAllow_multiActionUserOp() (gas: 223111) -MultiSig_TestSuite_Test:test_notAllow_nonceReuse() (gas: 248536) -MultiSig_TestSuite_Test:test_notAllow_notDelegationManager() (gas: 17384) -MultiSig_TestSuite_Test:test_notAllow_notEntryPoint() (gas: 17386) -NonceEnforcerTest:test_allow_incrementingId() (gas: 45496) -NonceEnforcerTest:test_allow_validId() (gas: 27573) -NonceEnforcerTest:test_decodedTheTerms() (gas: 11687) -NonceEnforcerTest:test_invalid_decodedTheTerms() (gas: 14368) -NonceEnforcerTest:test_notAllow_invalidId() (gas: 62867) -PasswordEnforcerTest:test_userInputCorrectArgsWorks() (gas: 17351) -PasswordEnforcerTest:test_userInputCorrectArgsWorksWithOffchainDelegation() (gas: 324319) -PasswordEnforcerTest:test_userInputCorrectArgsWorksWithOnchainDelegation() (gas: 515138) -PasswordEnforcerTest:test_userInputIncorrectArgs() (gas: 18166) -PasswordEnforcerTest:test_userInputIncorrectArgsWithOnchainDelegation() (gas: 475032) -PasswordEnforcerTest:test_userInputIncorrectArgsWorksWithOffchainDelegation() (gas: 283210) -StorageUtilsLibTest:testToBool() (gas: 17570) -TimestampEnforcerTest:test_methodCanBeCalledAfterTimestamp() (gas: 18300) -TimestampEnforcerTest:test_methodCanBeCalledAfterTimestampIntegration() (gas: 632716) -TimestampEnforcerTest:test_methodCanBeCalledBeforeTimestamp() (gas: 17780) -TimestampEnforcerTest:test_methodCanBeCalledInsideTimestampRange() (gas: 18525) -TimestampEnforcerTest:test_methodFailsIfCalledAfterTimestamp() (gas: 19141) -TimestampEnforcerTest:test_methodFailsIfCalledAfterTimestampRange() (gas: 19573) -TimestampEnforcerTest:test_methodFailsIfCalledBeforeTimestampRange() (gas: 18762) -TimestampEnforcerTest:test_methodFailsIfCalledTimestamp() (gas: 18568) -TimestampEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 17578) -TypehashTest:test_CaveatTypehash() (gas: 7811) -TypehashTest:test_DelegationTypehash() (gas: 18857) -TypehashTest:test_EIP712DomainTypehash() (gas: 10048) -ValueLteEnforcerTest:test_allow_decodeTerms() (gas: 11764) -ValueLteEnforcerTest:test_allow_valueLte() (gas: 15950) -ValueLteEnforcerTest:test_notAllow_decodeTerms() (gas: 17198) -ValueLteEnforcerTest:test_notAllow_valueGt() (gas: 15174) \ No newline at end of file +AllowedCalldataEnforcerTest:test_failsWithInvalidTermsLength() (gas: 19079) +AllowedCalldataEnforcerTest:test_methodCanBeCalledWithSpecificMetadata() (gas: 21884) +AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualDynamicArrayParam() (gas: 24762) +AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualDynamicStringParam() (gas: 24132) +AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualParam() (gas: 18810) +AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualParamIntegration() (gas: 411051) +AllowedCalldataEnforcerTest:test_singleMethodCanNotBeCalledWithNonEqualParamIntegration() (gas: 257322) +AllowedCalldataEnforcerTest:test_singleMethodCanNotCalledWithInvalidTermsSize() (gas: 17686) +AllowedCalldataEnforcerTest:test_singleMethodCanNotCalledWithNonEqualParam() (gas: 19293) +AllowedMethodsEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 11216) +AllowedMethodsEnforcerTest:test_methodCanBeSingleMethodIntegration() (gas: 398049) +AllowedMethodsEnforcerTest:test_multiMethodCanBeCalled() (gas: 17942) +AllowedMethodsEnforcerTest:test_notAllow_invalidActionLength() (gas: 15364) +AllowedMethodsEnforcerTest:test_onlyApprovedMethodsCanBeCalled() (gas: 18533) +AllowedMethodsEnforcerTest:test_onlyApprovedMethodsCanBeCalledIntegration() (gas: 256820) +AllowedMethodsEnforcerTest:test_singleMethodCanBeCalled() (gas: 16270) +AllowedTargetsEnforcerTest:testFToken1() (gas: 2395) +AllowedTargetsEnforcerTest:testFToken2() (gas: 2437) +AllowedTargetsEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 11258) +AllowedTargetsEnforcerTest:test_multiTargetCanBeCalled() (gas: 21791) +AllowedTargetsEnforcerTest:test_multiTargetCanBeCalledIntegration() (gas: 659387) +AllowedTargetsEnforcerTest:test_onlyApprovedMethodsCanBeCalledIntegration() (gas: 265602) +AllowedTargetsEnforcerTest:test_onlyApprovedTargetsCanBeCalled() (gas: 24379) +AllowedTargetsEnforcerTest:test_singleTargetCanBeCalled() (gas: 15944) +BlockNumberEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 8962) +BlockNumberEnforcerTest:test_methodCanBeCalledAfterBlockNumber() (gas: 15599) +BlockNumberEnforcerTest:test_methodCanBeCalledAfterBlockNumberIntegration() (gas: 383885) +BlockNumberEnforcerTest:test_methodCanBeCalledBeforeBlockNumber() (gas: 15337) +BlockNumberEnforcerTest:test_methodCanBeCalledInsideBlockNumberRange() (gas: 15734) +BlockNumberEnforcerTest:test_methodFailsIfCalledAfterBlockNumber() (gas: 16185) +BlockNumberEnforcerTest:test_methodFailsIfCalledAfterBlockNumberRange() (gas: 16361) +BlockNumberEnforcerTest:test_methodFailsIfCalledBeforeBlockNumber() (gas: 15769) +BlockNumberEnforcerTest:test_methodFailsIfCalledBeforeBlockNumberRange() (gas: 15849) +CounterfactualAssetsTest:test_allow_createNftAndDelegateWithCaveatsAndRedelegate_offchain() (gas: 2844294) +CounterfactualAssetsTest:test_allow_createNftAndDelegateWithCaveats_offchain() (gas: 2786127) +CounterfactualAssetsTest:test_allow_createNftAndDelegate_offchain() (gas: 2748183) +DelegationManagerTest:test_allow_anyDelegateReads() (gas: 5650) +DelegationManagerTest:test_allow_contractNameReads() (gas: 7230) +DelegationManagerTest:test_allow_contractVersionReads() (gas: 7236) +DelegationManagerTest:test_allow_domainHashReads() (gas: 9454) +DelegationManagerTest:test_allow_domainHashReadsWhenChainIdChanges() (gas: 12627) +DelegationManagerTest:test_allow_domainVersionReads() (gas: 7073) +DelegationManagerTest:test_allow_getDelegationHash() (gas: 15921) +DelegationManagerTest:test_allow_rootAuthorityReads() (gas: 5519) +DelegationManagerTest:test_notAllow_crossDelegationManagerReplays() (gas: 2254890) +DelegationManagerTest:test_notAllow_invalidSignatureReturns() (gas: 129277) +DelegationManagerTest:test_notAllow_invalidSignatureReverts() (gas: 139411) +DelegationManagerTest:test_ownership_transferAndAcceptOwnership() (gas: 36078) +DelegationManagerTest:test_pausability_allowsOwnerToPause() (gas: 39540) +DelegationManagerTest:test_pausability_allowsOwnerToPauseRedemptions() (gas: 37999) +DelegationManagerTest:test_pausability_allowsOwnerToUnpause() (gas: 29340) +DelegationManagerTest:test_pausability_failsToPauseIfNotOwner() (gas: 17635) +DelegationManagerTest:test_pausability_failsToPauseWhenActivePause() (gas: 37313) +DelegationManagerTest:test_pausability_failsToPauseWhenActiveUnpause() (gas: 15075) +DelegationManagerTest:test_pausability_failsToUnpauseIfNotOwner() (gas: 41317) +DelegationManagerTest:test_pausability_validateInitialPauseState() (gas: 1814475) +DeployedEnforcerTest:test_computesAPredictedAddress() (gas: 12693) +DeployedEnforcerTest:test_deploysIfNonExistent() (gas: 165078) +DeployedEnforcerTest:test_deploysIfNonExistentAndAllowsToUseItIntegration() (gas: 435554) +DeployedEnforcerTest:test_doesNotDeployIfExistent() (gas: 118116) +DeployedEnforcerTest:test_revertIfContractIsEmpty() (gas: 55184) +DeployedEnforcerTest:test_revertIfPredictedAddressDoesNotMatch() (gas: 111361) +DeployedEnforcerTest:test_revertIfTermsLengthIsInvalid() (gas: 23352) +DeployedEnforcerTest:test_revertsIfBytecodeDoesntExist() (gas: 111019) +ERC20BalanceGteEnforcerTest:test_allow_ifBalanceIncreases() (gas: 135032) +ERC20BalanceGteEnforcerTest:test_decodedTheTerms() (gas: 9393) +ERC20BalanceGteEnforcerTest:test_invalid_decodedTheTerms() (gas: 15278) +ERC20BalanceGteEnforcerTest:test_invalid_tokenAddress() (gas: 53321) +ERC20BalanceGteEnforcerTest:test_notAllow_expectingOverflow() (gas: 72896) +ERC20BalanceGteEnforcerTest:test_notAllow_insufficientIncrease() (gas: 98127) +ERC20BalanceGteEnforcerTest:test_notAllow_reenterALockedEnforcer() (gas: 154894) +ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidContract() (gas: 31848) +ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidMethod() (gas: 30295) +ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidTermsLength() (gas: 29066) +ERC20TransferAmountEnforcerTest:test_notAllow_invalidActionLength() (gas: 29101) +ERC20TransferAmountEnforcerTest:test_transferFailsAboveAllowance() (gas: 548288) +ERC20TransferAmountEnforcerTest:test_transferFailsIfCalledAboveAllowance() (gas: 51151) +ERC20TransferAmountEnforcerTest:test_transferSucceedsIfCalledBelowAllowance() (gas: 56151) +EncoderLibTest:test_ShouldEncodeAnArrayOfCaveats() (gas: 10875) +EncoderLibTest:test_ShouldEncodeOneCaveat() (gas: 5517) +EncoderLibTest:test_shouldEncodeOneDelegation() (gas: 8797) +HybridDeleGator_Test:test_allow_addKey() (gas: 644669) +HybridDeleGator_Test:test_allow_erc173InterfaceId() (gas: 13048) +HybridDeleGator_Test:test_allow_removeKey() (gas: 1032990) +HybridDeleGator_Test:test_allow_replaceEOAWithEOA() (gas: 173966) +HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256() (gas: 276817) +HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256WithOffchainDelegation() (gas: 1075663) +HybridDeleGator_Test:test_allow_replaceEOAWithP256() (gas: 268375) +HybridDeleGator_Test:test_allow_signatureWithEOA() (gas: 38383) +HybridDeleGator_Test:test_allow_signatureWithP256() (gas: 410596) +HybridDeleGator_Test:test_allow_signingWithWebAuthn() (gas: 646777) +HybridDeleGator_Test:test_allow_upgradingHybridDeleGator() (gas: 662110) +HybridDeleGator_Test:test_error_replacedSignersInputsMismatch() (gas: 38834) +HybridDeleGator_Test:test_error_replacedSignersToEmpty() (gas: 16079) +HybridDeleGator_Test:test_events_replacedSigners() (gas: 109594) +HybridDeleGator_Test:test_fails_signingWithWebAuthnWithInvalidType() (gas: 219318) +HybridDeleGator_Test:test_initialize_multipleP256OneEOA() (gas: 1032330) +HybridDeleGator_Test:test_initialize_multipleP256ZeroEOA() (gas: 1010140) +HybridDeleGator_Test:test_initialize_zeroP256OneEOA() (gas: 153887) +HybridDeleGator_Test:test_keyAdded_addKey() (gas: 646244) +HybridDeleGator_Test:test_keyAdded_initialize() (gas: 260213) +HybridDeleGator_Test:test_keyRemoved_removeKey() (gas: 1033640) +HybridDeleGator_Test:test_notAllow_addKeyNotOnCurve() (gas: 17527) +HybridDeleGator_Test:test_notAllow_addingAnEmptyKey() (gas: 15327) +HybridDeleGator_Test:test_notAllow_addingExistingKey() (gas: 24863) +HybridDeleGator_Test:test_notAllow_invalidKeyOnDeploy() (gas: 99666) +HybridDeleGator_Test:test_notAllow_invalidSignatureLength() (gas: 22665) +HybridDeleGator_Test:test_notAllow_removingLastKeyViaEOA() (gas: 30437) +HybridDeleGator_Test:test_notAllow_removingLastKeyViaP256() (gas: 27194) +HybridDeleGator_Test:test_notAllow_removingNonExistantKey() (gas: 22288) +HybridDeleGator_Test:test_notAllow_renounceOwnership_Direct() (gas: 19419) +HybridDeleGator_Test:test_notAllow_transferOwnership_directNonOwner() (gas: 16510) +HybridDeleGator_Test:test_notAllow_transferOwnership_directOwner() (gas: 18498) +HybridDeleGator_Test:test_reinitialize_clearsAndSetSigners() (gas: 185988) +HybridDeleGator_Test:test_reinitialize_keepAndSetSigners() (gas: 204732) +HybridDeleGator_Test:test_removeP256KeyAndRearrangeStoredKeyIdHashes() (gas: 173344) +HybridDeleGator_Test:test_return_KeyIdHashes() (gas: 645970) +HybridDeleGator_Test:test_upgradeMultipleTimes() (gas: 523724) +HybridDeleGator_Test:test_upgradeWithoutStorageCleanup() (gas: 438130) +HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 310713) +HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 154109) +HybridDeleGator_TestSuite_EOA_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 261064) +HybridDeleGator_TestSuite_EOA_Test:test_allow_disableOffchainDelegation() (gas: 515436) +HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 106774) +HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 137311) +HybridDeleGator_TestSuite_EOA_Test:test_allow_getDeposit() (gas: 15879) +HybridDeleGator_TestSuite_EOA_Test:test_allow_getEntryPoint() (gas: 12754) +HybridDeleGator_TestSuite_EOA_Test:test_allow_getNonce() (gas: 16208) +HybridDeleGator_TestSuite_EOA_Test:test_allow_getNonceWithKey() (gas: 16334) +HybridDeleGator_TestSuite_EOA_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 300056) +HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionCombination_UserOp() (gas: 306837) +HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 308896) +HybridDeleGator_TestSuite_EOA_Test:test_allow_multiAction_UserOp() (gas: 205013) +HybridDeleGator_TestSuite_EOA_Test:test_allow_offchainOpenDelegation() (gas: 323902) +HybridDeleGator_TestSuite_EOA_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 174715) +HybridDeleGator_TestSuite_EOA_Test:test_allow_receiveNativeToken() (gas: 17290) +HybridDeleGator_TestSuite_EOA_Test:test_allow_resetDisabledDelegation() (gas: 273097) +HybridDeleGator_TestSuite_EOA_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 273461) +HybridDeleGator_TestSuite_EOA_Test:test_allow_withdrawDeposit() (gas: 253649) +HybridDeleGator_TestSuite_EOA_Test:test_emit_executedActionEvent() (gas: 69655) +HybridDeleGator_TestSuite_EOA_Test:test_emit_sentPrefund() (gas: 70151) +HybridDeleGator_TestSuite_EOA_Test:test_erc165_supportsInterface() (gas: 19014) +HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidAuthority() (gas: 275718) +HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidDelegate() (gas: 218929) +HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidDelegator() (gas: 187459) +HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidRootAuthority() (gas: 70344) +HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidSignature() (gas: 233699) +HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidSigner() (gas: 233478) +HybridDeleGator_TestSuite_EOA_Test:test_error_NoDelegationsProvided() (gas: 209566) +HybridDeleGator_TestSuite_EOA_Test:test_event_Deposited() (gas: 186926) +HybridDeleGator_TestSuite_EOA_Test:test_executesFirstRootAuthorityFound() (gas: 269012) +HybridDeleGator_TestSuite_EOA_Test:test_executionRevertsWithoutReason() (gas: 31686) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 75118) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 76537) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 283684) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 187492) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_delegationWithoutSignature() (gas: 34268) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 302303) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_disablingInvalidDelegation() (gas: 187581) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_emptyAction_UserOp() (gas: 169303) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 199391) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 74187) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidEntryPoint() (gas: 3178940) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidRedeemDelegationData() (gas: 48548) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidUserOpSignature() (gas: 132488) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 214398) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_multiActionUserOp() (gas: 192860) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_nonceReuse() (gas: 209787) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_notDelegationManager() (gas: 16708) +HybridDeleGator_TestSuite_EOA_Test:test_notAllow_notEntryPoint() (gas: 16643) +HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 1461507) +HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 920655) +HybridDeleGator_TestSuite_P256_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 1019158) +HybridDeleGator_TestSuite_P256_Test:test_allow_disableOffchainDelegation() (gas: 2404096) +HybridDeleGator_TestSuite_P256_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 476935) +HybridDeleGator_TestSuite_P256_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 507472) +HybridDeleGator_TestSuite_P256_Test:test_allow_getDeposit() (gas: 15879) +HybridDeleGator_TestSuite_P256_Test:test_allow_getEntryPoint() (gas: 12754) +HybridDeleGator_TestSuite_P256_Test:test_allow_getNonce() (gas: 16208) +HybridDeleGator_TestSuite_P256_Test:test_allow_getNonceWithKey() (gas: 16334) +HybridDeleGator_TestSuite_P256_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 1065126) +HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionCombination_UserOp() (gas: 1078370) +HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 1457506) +HybridDeleGator_TestSuite_P256_Test:test_allow_multiAction_UserOp() (gas: 573813) +HybridDeleGator_TestSuite_P256_Test:test_allow_offchainOpenDelegation() (gas: 1450370) +HybridDeleGator_TestSuite_P256_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 930472) +HybridDeleGator_TestSuite_P256_Test:test_allow_receiveNativeToken() (gas: 17290) +HybridDeleGator_TestSuite_P256_Test:test_allow_resetDisabledDelegation() (gas: 1037480) +HybridDeleGator_TestSuite_P256_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 1035884) +HybridDeleGator_TestSuite_P256_Test:test_allow_withdrawDeposit() (gas: 1012917) +HybridDeleGator_TestSuite_P256_Test:test_emit_executedActionEvent() (gas: 69655) +HybridDeleGator_TestSuite_P256_Test:test_emit_sentPrefund() (gas: 70151) +HybridDeleGator_TestSuite_P256_Test:test_erc165_supportsInterface() (gas: 19014) +HybridDeleGator_TestSuite_P256_Test:test_error_InvalidAuthority() (gas: 1430056) +HybridDeleGator_TestSuite_P256_Test:test_error_InvalidDelegate() (gas: 612259) +HybridDeleGator_TestSuite_P256_Test:test_error_InvalidDelegator() (gas: 575654) +HybridDeleGator_TestSuite_P256_Test:test_error_InvalidRootAuthority() (gas: 466977) +HybridDeleGator_TestSuite_P256_Test:test_error_InvalidSignature() (gas: 624753) +HybridDeleGator_TestSuite_P256_Test:test_error_InvalidSigner() (gas: 624532) +HybridDeleGator_TestSuite_P256_Test:test_error_NoDelegationsProvided() (gas: 594641) +HybridDeleGator_TestSuite_P256_Test:test_event_Deposited() (gas: 566929) +HybridDeleGator_TestSuite_P256_Test:test_executesFirstRootAuthorityFound() (gas: 1427080) +HybridDeleGator_TestSuite_P256_Test:test_executionRevertsWithoutReason() (gas: 31686) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 76900) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 78320) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 1444840) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 571310) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_delegationWithoutSignature() (gas: 34268) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 1076766) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_disablingInvalidDelegation() (gas: 576711) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_emptyAction_UserOp() (gas: 558220) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 591984) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 76049) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidEntryPoint() (gas: 3182587) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidRedeemDelegationData() (gas: 50410) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidUserOpSignature() (gas: 132806) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 607728) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_multiActionUserOp() (gas: 576810) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_nonceReuse() (gas: 966786) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_notDelegationManager() (gas: 16708) +HybridDeleGator_TestSuite_P256_Test:test_notAllow_notEntryPoint() (gas: 16643) +IdEnforcerEnforcerTest:testFToken1() (gas: 2439) +IdEnforcerEnforcerTest:test_blocksDelegationWithRepeatedNonce() (gas: 49111) +IdEnforcerEnforcerTest:test_decodedTheTerms() (gas: 6304) +IdEnforcerEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 13237) +IdEnforcerEnforcerTest:test_methodFailsIfNonceAlreadyUsed() (gas: 407040) +InviteTest:test_createADeleGatorForBobAndDelegate() (gas: 555272) +InviteTest:test_createADeleGatorForBobAndSend() (gas: 426810) +LimitedCallsEnforcerTest:test_methodCanBeCalledBelowLimitNumber() (gas: 53639) +LimitedCallsEnforcerTest:test_methodFailsAboveLimitIntegration() (gas: 410960) +LimitedCallsEnforcerTest:test_methodFailsIfCalledAboveLimitNumber() (gas: 53929) +LimitedCallsEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 13393) +MultiSigDeleGatorTest:test_DelegationManagerSetEvent() (gas: 2802132) +MultiSigDeleGatorTest:test_ImplementationUsesMaxThreshold() (gas: 7584) +MultiSigDeleGatorTest:test_InitializedImplementationEvent() (gas: 2802004) +MultiSigDeleGatorTest:test_InitializedSignersEvents() (gas: 334328) +MultiSigDeleGatorTest:test_ReinitializedSignersEvents() (gas: 140910) +MultiSigDeleGatorTest:test_allow_addSigner() (gas: 81864) +MultiSigDeleGatorTest:test_allow_deploySCAWithInitCode() (gas: 411169) +MultiSigDeleGatorTest:test_allow_getMaxSigners() (gas: 10474) +MultiSigDeleGatorTest:test_allow_getSignersCount() (gas: 12657) +MultiSigDeleGatorTest:test_allow_invokeOffchainDelegationWithMultipleSigners() (gas: 287181) +MultiSigDeleGatorTest:test_allow_removeSigner() (gas: 220380) +MultiSigDeleGatorTest:test_allow_replaceSigner() (gas: 222189) +MultiSigDeleGatorTest:test_allow_updateMultiSigParameters_base() (gas: 547816) +MultiSigDeleGatorTest:test_allow_updatingThreshold() (gas: 81137) +MultiSigDeleGatorTest:test_error_Init_AlreadyASigner() (gas: 164347) +MultiSigDeleGatorTest:test_error_Init_InvalidSignerAddress() (gas: 95386) +MultiSigDeleGatorTest:test_error_Init_InvalidSignersLength() (gas: 264732) +MultiSigDeleGatorTest:test_error_Init_InvalidThreshold() (gas: 182347) +MultiSigDeleGatorTest:test_error_Init_thresholdGreaterThanSigners() (gas: 119497) +MultiSigDeleGatorTest:test_error_updateSigParamatersAlreadyASigner() (gas: 71786) +MultiSigDeleGatorTest:test_error_updateSigParamatersContractNewSigner() (gas: 24948) +MultiSigDeleGatorTest:test_error_updateSigParamatersZeroNewSigner() (gas: 20222) +MultiSigDeleGatorTest:test_error_updateSigParametersInvalidThreshold() (gas: 17404) +MultiSigDeleGatorTest:test_notAllow_addSigner() (gas: 1579287) +MultiSigDeleGatorTest:test_notAllow_invalidSignatureLength() (gas: 163315) +MultiSigDeleGatorTest:test_notAllow_invalidSigners() (gas: 177010) +MultiSigDeleGatorTest:test_notAllow_removeSigner() (gas: 110994) +MultiSigDeleGatorTest:test_notAllow_replaceSigner() (gas: 53557) +MultiSigDeleGatorTest:test_notAllow_signerReuse() (gas: 166498) +MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_access() (gas: 37408) +MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_maxNumberOfSigners() (gas: 31099) +MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_threshold() (gas: 32235) +MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_thresholdKeepingSigners() (gas: 26762) +MultiSigDeleGatorTest:test_notAllow_updatingThreshold() (gas: 86116) +MultiSigDeleGatorTest:test_reinitialize_clearsAndSetSigners() (gas: 128542) +MultiSigDeleGatorTest:test_reinitialize_keepAndSetSigners() (gas: 146141) +MultiSigDeleGatorTest:test_return_ifAnAddressIsAValidSigner() (gas: 20724) +MultiSigDeleGatorTest:test_unauthorizedReinitializeCall() (gas: 24240) +MultiSig_TestSuite_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 324649) +MultiSig_TestSuite_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 163346) +MultiSig_TestSuite_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 270369) +MultiSig_TestSuite_Test:test_allow_disableOffchainDelegation() (gas: 531088) +MultiSig_TestSuite_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 111381) +MultiSig_TestSuite_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 141919) +MultiSig_TestSuite_Test:test_allow_getDeposit() (gas: 15879) +MultiSig_TestSuite_Test:test_allow_getEntryPoint() (gas: 12754) +MultiSig_TestSuite_Test:test_allow_getNonce() (gas: 16186) +MultiSig_TestSuite_Test:test_allow_getNonceWithKey() (gas: 16400) +MultiSig_TestSuite_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 309361) +MultiSig_TestSuite_Test:test_allow_multiActionCombination_UserOp() (gas: 316099) +MultiSig_TestSuite_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 319260) +MultiSig_TestSuite_Test:test_allow_multiAction_UserOp() (gas: 209598) +MultiSig_TestSuite_Test:test_allow_offchainOpenDelegation() (gas: 334242) +MultiSig_TestSuite_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 183952) +MultiSig_TestSuite_Test:test_allow_receiveNativeToken() (gas: 17290) +MultiSig_TestSuite_Test:test_allow_resetDisabledDelegation() (gas: 280225) +MultiSig_TestSuite_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 280633) +MultiSig_TestSuite_Test:test_allow_withdrawDeposit() (gas: 260866) +MultiSig_TestSuite_Test:test_emit_executedActionEvent() (gas: 69611) +MultiSig_TestSuite_Test:test_emit_sentPrefund() (gas: 72559) +MultiSig_TestSuite_Test:test_erc165_supportsInterface() (gas: 18729) +MultiSig_TestSuite_Test:test_error_InvalidAuthority() (gas: 289678) +MultiSig_TestSuite_Test:test_error_InvalidDelegate() (gas: 225199) +MultiSig_TestSuite_Test:test_error_InvalidDelegator() (gas: 192155) +MultiSig_TestSuite_Test:test_error_InvalidRootAuthority() (gas: 74973) +MultiSig_TestSuite_Test:test_error_InvalidSignature() (gas: 242928) +MultiSig_TestSuite_Test:test_error_InvalidSigner() (gas: 242707) +MultiSig_TestSuite_Test:test_error_NoDelegationsProvided() (gas: 215836) +MultiSig_TestSuite_Test:test_event_Deposited() (gas: 191511) +MultiSig_TestSuite_Test:test_executesFirstRootAuthorityFound() (gas: 282970) +MultiSig_TestSuite_Test:test_executionRevertsWithoutReason() (gas: 31664) +MultiSig_TestSuite_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 76690) +MultiSig_TestSuite_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 78110) +MultiSig_TestSuite_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 297643) +MultiSig_TestSuite_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 192188) +MultiSig_TestSuite_Test:test_notAllow_delegationWithoutSignature() (gas: 34335) +MultiSig_TestSuite_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 310983) +MultiSig_TestSuite_Test:test_notAllow_disablingInvalidDelegation() (gas: 192189) +MultiSig_TestSuite_Test:test_notAllow_emptyAction_UserOp() (gas: 173888) +MultiSig_TestSuite_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 205659) +MultiSig_TestSuite_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 75759) +MultiSig_TestSuite_Test:test_notAllow_invalidEntryPoint() (gas: 3182070) +MultiSig_TestSuite_Test:test_notAllow_invalidRedeemDelegationData() (gas: 50119) +MultiSig_TestSuite_Test:test_notAllow_invalidUserOpSignature() (gas: 137019) +MultiSig_TestSuite_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 220668) +MultiSig_TestSuite_Test:test_notAllow_multiActionUserOp() (gas: 197445) +MultiSig_TestSuite_Test:test_notAllow_nonceReuse() (gas: 215451) +MultiSig_TestSuite_Test:test_notAllow_notDelegationManager() (gas: 16686) +MultiSig_TestSuite_Test:test_notAllow_notEntryPoint() (gas: 16621) +NonceEnforcerTest:test_allow_incrementingId() (gas: 42105) +NonceEnforcerTest:test_allow_validId() (gas: 24403) +NonceEnforcerTest:test_decodedTheTerms() (gas: 9365) +NonceEnforcerTest:test_invalid_decodedTheTerms() (gas: 12704) +NonceEnforcerTest:test_notAllow_invalidId() (gas: 54844) +PasswordEnforcerTest:test_userInputCorrectArgsWorks() (gas: 14996) +PasswordEnforcerTest:test_userInputCorrectArgsWorksWithOffchainDelegation() (gas: 279347) +PasswordEnforcerTest:test_userInputIncorrectArgs() (gas: 15445) +PasswordEnforcerTest:test_userInputIncorrectArgsWithOffchainDelegation() (gas: 253774) +PasswordEnforcerTest:test_userInputIncorrectArgsWorksWithOffchainDelegation() (gas: 243638) +StorageUtilsLibTest:testToBool() (gas: 11185) +TimestampEnforcerTest:test_methodCanBeCalledAfterTimestamp() (gas: 15761) +TimestampEnforcerTest:test_methodCanBeCalledAfterTimestampIntegration() (gas: 384168) +TimestampEnforcerTest:test_methodCanBeCalledBeforeTimestamp() (gas: 15336) +TimestampEnforcerTest:test_methodCanBeCalledInsideTimestampRange() (gas: 15873) +TimestampEnforcerTest:test_methodFailsIfCalledAfterTimestamp() (gas: 16254) +TimestampEnforcerTest:test_methodFailsIfCalledAfterTimestampRange() (gas: 16473) +TimestampEnforcerTest:test_methodFailsIfCalledBeforeTimestampRange() (gas: 15848) +TimestampEnforcerTest:test_methodFailsIfCalledTimestamp() (gas: 15770) +TimestampEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 13421) +TypehashTest:test_CaveatTypehash() (gas: 7615) +TypehashTest:test_DelegationTypehash() (gas: 18191) +TypehashTest:test_EIP712DomainTypehash() (gas: 9844) +ValueLteEnforcerTest:test_allow_decodeTerms() (gas: 9277) +ValueLteEnforcerTest:test_allow_valueLte() (gas: 12381) +ValueLteEnforcerTest:test_notAllow_decodeTerms() (gas: 14911) +ValueLteEnforcerTest:test_notAllow_valueGt() (gas: 12958) \ No newline at end of file diff --git a/documents/DelegationManager.md b/documents/DelegationManager.md index db05768..bcf280e 100644 --- a/documents/DelegationManager.md +++ b/documents/DelegationManager.md @@ -8,24 +8,17 @@ A Delegation Manager is responsible for validating delegations and triggering th ## Delegations -Users can allow other contracts or EOAs to invoke an Action directly from their DeleGator Smart Account through a Delegation. There are 2 flows for delegating: onchain and offchain. Both flows require creating a Delegation and sharing some additional data offchain to the delegate for them to be able to redeem the Delegation. +Users can allow other contracts or EOAs to invoke an action directly from their DeleGator Smart Account through a delegation. Creating a delegation requires specifying a delegate and some optional data such caveats (more detail below) and an authority. Delegations are stored offchain and helper utilities that assist with the delegation lifecycle are provided in the SDK. -> NOTE: onchain Delegations are validated at the time of creation, not at the time of execution. This means if anything regarding a DeleGator’s control scheme is changed, the onchain Delegation is not impacted. Contrast this with an offchain Delegation, which is validated at the time of execution. +> NOTE: Delegations are validated at execution time, so the signature may become invalid if the conditions of a valid signature change. > -> Example: Alice delegates to Bob the ability to spend her USDC with a 1 of 1 MultiSig DeleGator Account. She then updates her DeleGator Account to a 2 of 3 MultiSig. -> -> - If she delegated onchain, Bob is still able to spend her USDC. -> - If she delegated offchain, the signature will no longer be valid and Bob is not able to spend her USDC. +> Example: Alice delegates to Bob the ability to spend her USDC with a 1 of 1 MultiSig DeleGator Account. She then updates her DeleGator Account to a 2 of 3 MultiSig. When Bob redeems the delegation from Alice, it will fail since the signed delegation is no longer valid. # MetaMask's Delegation Manager ## Creating a Delegation -Users can create a `Delegation` and provide it to a delegate in the form of an onchain delegation or an offchain delegation. - -### Onchain Delegations - -Onchain Delegations are done through calling the `delegate` method on a DeleGator or DelegationManager. This validates the delegation at this time and the redeemer only needs the `Delegation` to redeem it (no signature needed). +Users can create a `Delegation` and provide it to a delegate in the form of an offchain delegation. ### Offchain Delegations @@ -44,7 +37,7 @@ Our `DelegationManager` implementation: 1. `redeemDelegation` consumes a list of delegations (`Delegation[]`) and an `Action` to be executed > NOTE: Delegations are ordered from leaf to root. The last delegation in the array must have the root authority. 2. Validates the `msg.sender` calling `redeemDelegation` is allowed to do so -3. Validates the signatures of offchain delegations and that onchain delegations have already been verified +3. Validates the signatures of offchain delegations. 4. Checks if any of the delegations being redeemed are disabled 5. Ensures each delegation has sufficient authority to execute, given by the previous delegation or by being a root delegation 6. Calls `beforeHook` for all delegations (from leaf to root delegation) diff --git a/src/DeleGatorCore.sol b/src/DeleGatorCore.sol index 5ab1b8b..f87b384 100644 --- a/src/DeleGatorCore.sol +++ b/src/DeleGatorCore.sol @@ -249,15 +249,6 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel entryPoint.withdrawTo(_withdrawAddress, _withdrawAmount); } - /** - * @notice Delegates authority to an address and caches the delegation hash onchain - * @dev Forwards a call to the DelegationManager to delegate - * @param _delegation The delegation to be stored - */ - function delegate(Delegation calldata _delegation) external onlyEntryPointOrSelf { - delegationManager.delegate(_delegation); - } - /** * @notice Disables a delegation from being used * @param _delegation The delegation to be disabled @@ -305,15 +296,6 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel return delegationManager.disabledDelegations(_delegationHash); } - /** - * @notice Checks if the delegation hash has been cached onchain - * @param _delegationHash the hash of the delegation to check for - * @return bool is the delegation stored onchain - */ - function isDelegationOnchain(bytes32 _delegationHash) external view returns (bool) { - return delegationManager.onchainDelegations(_delegationHash); - } - /** * @notice Gets the current account's deposit in the entry point * @dev Related: ERC4337 diff --git a/src/DelegationManager.sol b/src/DelegationManager.sol index 078e793..7aca4ae 100644 --- a/src/DelegationManager.sol +++ b/src/DelegationManager.sol @@ -17,9 +17,8 @@ import { ERC1271Lib } from "./libraries/ERC1271Lib.sol"; /** * @title DelegationManager - * @notice This contract is used to manage delegations. Users can cache hashes of delegations onchain within this contract. - * Delegations - * can be validated and executed through this contract. + * @notice This contract is used to manage delegations. + * Delegations can be validated and executed through this contract. */ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 { using MessageHashUtils for bytes32; @@ -41,9 +40,6 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 /// @dev Special delegate value. Allows any delegate to redeem the delegation address public constant ANY_DELEGATE = address(0xa11); - /// @dev A mapping of delegation hashes that have been cached onchain - mapping(bytes32 delegationHash => bool isOnchain) public onchainDelegations; - /// @dev A mapping of delegation hashes that have been disabled by the delegator mapping(bytes32 delegationHash => bool isDisabled) public disabledDelegations; @@ -86,24 +82,9 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 _unpause(); } - /** - * @notice This method is used to cache a delegation's hash onchain for future use - * @dev This method MUST be called by the delegator - * @dev Caching a delegation onchain allows the system to trust that the delegation was already authorized at the time of - * redemption - * @param _delegation The delegation to be stored - */ - function delegate(Delegation calldata _delegation) external onlyDeleGator(_delegation.delegator) { - bytes32 delegationHash_ = getDelegationHash(_delegation); - if (onchainDelegations[delegationHash_]) revert AlreadyExists(); - onchainDelegations[delegationHash_] = true; - emit Delegated(delegationHash_, _delegation.delegator, _delegation.delegate, _delegation); - } - /** * @notice This method is used to disable a delegation. Disabled delegations will fail upon redemption. * @dev This method MUST be called by the delegator - * @dev This method supports disabling offchain and onchain delegations * @param _delegation The delegation to be disabled */ function disableDelegation(Delegation calldata _delegation) external onlyDeleGator(_delegation.delegator) { @@ -116,7 +97,6 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 /** * @notice This method is used to enable a delegation * @dev This method MUST be called by the delegator - * @dev This method supports enabling offchain and onchain delegations * @dev This method is only needed when a delegation has previously been disabled * @param _delegation The delegation to be disabled */ @@ -135,9 +115,7 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 * changes, disabled delegations or arbitrary caveat * restrictions. Be sure to validate offchain before submitting anything onchain. * @dev Delegations are ordered from leaf to root. The last delegation in the array must have the root authority. - * @dev Delegations can come in the form of offchain or onchain delegations. Offchain delegations are signed by the delegator - * and are validated at the time of redemption. Onchain delegations are validated at the time of delegation and are trusted to - * be valid at the time of redemption. + * @dev Delegations are signed by the delegator and are validated at the time of redemption. * @dev Caveats are enforced with the order: `beforeHook` from leaf to root, execute action, `afterHook` from root to leaf * @param _data the data used to validate the authority given to execute the action. * @param _action the action to be executed @@ -164,29 +142,24 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 delegationHashes_[i] = EncoderLib._getDelegationHash(delegation_); if (delegation_.signature.length == 0) { - // Ensure that delegations without signatures have already been validated onchain - if (!onchainDelegations[delegationHashes_[i]]) { - revert InvalidDelegation(); - } + // Ensure that delegations without signatures revert + revert EmptySignature(); + } + // Check if the delegator is an EOA or a contract + address delegator_ = delegation_.delegator; + + if (delegator_.code.length == 0) { + // Validate delegation if it's an EOA + address result_ = + ECDSA.recover(MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[i]), delegation_.signature); + if (result_ != delegator_) revert InvalidSignature(); } else { - // If the delegation is offchain - // Check if the delegator is an EOA or a contract - address delegator_ = delegation_.delegator; - - if (delegator_.code.length == 0) { - // Validate delegation if it's an EOA - address result_ = ECDSA.recover( - MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[i]), delegation_.signature - ); - if (result_ != delegator_) revert InvalidSignature(); - } else { - // Validate delegation if it's a contract - bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[i]); - - bytes32 result_ = IERC1271(delegator_).isValidSignature(typedDataHash_, delegation_.signature); - if (result_ != ERC1271Lib.EIP1271_MAGIC_VALUE) { - revert InvalidSignature(); - } + // Validate delegation if it's a contract + bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[i]); + + bytes32 result_ = IERC1271(delegator_).isValidSignature(typedDataHash_, delegation_.signature); + if (result_ != ERC1271Lib.EIP1271_MAGIC_VALUE) { + revert InvalidSignature(); } } } @@ -254,7 +227,7 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 /** * @notice Creates a hash of a Delegation - * @dev Used in EIP712 signatures and as a key for storing delegations onchain + * @dev Used in EIP712 signatures and as a key for enabling and disabling delegations * @param _input A Delegation struct */ function getDelegationHash(Delegation calldata _input) public pure returns (bytes32) { diff --git a/src/interfaces/IDeleGatorCoreFull.sol b/src/interfaces/IDeleGatorCoreFull.sol index f8a4b30..d005384 100644 --- a/src/interfaces/IDeleGatorCoreFull.sol +++ b/src/interfaces/IDeleGatorCoreFull.sol @@ -49,8 +49,6 @@ interface IDeleGatorCoreFull is IDeleGatorCore, IERC165 { function withdrawDeposit(address payable _withdrawAddress, uint256 _withdrawAmount) external; - function delegate(Delegation calldata _delegation) external; - function disableDelegation(Delegation calldata _delegation) external; function enableDelegation(Delegation calldata _delegation) external; @@ -59,8 +57,6 @@ interface IDeleGatorCoreFull is IDeleGatorCore, IERC165 { function upgradeToAndCallAndRetainStorage(address _newImplementation, bytes memory _data) external payable; - function isDelegationOnchain(bytes32 _delegationHash) external view returns (bool); - function isDelegationDisabled(bytes32 _delegationHash) external view returns (bool); function entryPoint() external view returns (IEntryPoint); diff --git a/src/interfaces/IDelegationManager.sol b/src/interfaces/IDelegationManager.sol index 7880d38..d71d6b8 100644 --- a/src/interfaces/IDelegationManager.sol +++ b/src/interfaces/IDelegationManager.sol @@ -10,9 +10,6 @@ import { Action, Delegation } from "../utils/Types.sol"; interface IDelegationManager { ////////////////////////////// Events ////////////////////////////// - /// @dev Emitted when a delegation's hash is cached onchain - event Delegated(bytes32 indexed delegationHash, address indexed delegator, address indexed delegate, Delegation delegation); - /// @dev Emitted when a delegation is redeemed event RedeemedDelegation(address indexed rootDelegator, address indexed redeemer, Delegation delegation); @@ -51,15 +48,12 @@ interface IDelegationManager { /// @dev Error thrown when the signature provided is invalid error InvalidSignature(); - /// @dev Error thrown when the delegation provided hasn't been approved - error InvalidDelegation(); + /// @dev Error thrown when the signature is empty + error EmptySignature(); /// @dev Error thrown when the delegation provided is already disabled error AlreadyDisabled(); - /// @dev Error thrown when the delegation provided is already cached - error AlreadyExists(); - /// @dev Error thrown when the delegation provided is already enabled error AlreadyEnabled(); @@ -69,16 +63,12 @@ interface IDelegationManager { function unpause() external; - function delegate(Delegation calldata _delegation) external; - function enableDelegation(Delegation calldata _delegation) external; function disableDelegation(Delegation calldata _delegation) external; function disabledDelegations(bytes32 _delegationHash) external view returns (bool); - function onchainDelegations(bytes32 _delegationHash) external view returns (bool); - function getDelegationHash(Delegation calldata _delegation) external pure returns (bytes32); function redeemDelegation(bytes calldata _data, Action calldata _action) external; diff --git a/test/utils/SimpleFactory.sol b/src/utils/SimpleFactory.sol similarity index 100% rename from test/utils/SimpleFactory.sol rename to src/utils/SimpleFactory.sol diff --git a/test/DeleGatorTestSuite.t.sol b/test/DeleGatorTestSuite.t.sol index ee2e0ca..8537a01 100644 --- a/test/DeleGatorTestSuite.t.sol +++ b/test/DeleGatorTestSuite.t.sol @@ -56,7 +56,6 @@ abstract contract DeleGatorTestSuite is BaseTest { ////////////////////////////// Events ////////////////////////////// event Deposited(address indexed account, uint256 totalDeposit); - event Delegated(bytes32 indexed delegationHash, address indexed delegator, address indexed delegate, Delegation delegation); event EnabledDelegation( bytes32 indexed delegationHash, address indexed delegator, address indexed delegate, Delegation delegation ); @@ -96,31 +95,31 @@ abstract contract DeleGatorTestSuite is BaseTest { // should allow the delegator account to receive native tokens function test_allow_receiveNativeToken() public { - uint256 balanceBefore = address(users.alice.deleGator).balance; - (bool success,) = address(users.alice.deleGator).call{ value: 1 ether }(""); - assertTrue(success); - assertEq(address(users.alice.deleGator).balance, balanceBefore + 1 ether); + uint256 balanceBefore_ = address(users.alice.deleGator).balance; + (bool success_,) = address(users.alice.deleGator).call{ value: 1 ether }(""); + assertTrue(success_); + assertEq(address(users.alice.deleGator).balance, balanceBefore_ + 1 ether); } // should allow retrieval of the nonce function test_allow_getNonce() public { // Get Alice's nonce - uint256 nonce = users.alice.deleGator.getNonce(); - assertEq(nonce, 0); + uint256 nonce_ = users.alice.deleGator.getNonce(); + assertEq(nonce_, 0); } // should allow retrieval of the nonce function test_allow_getNonceWithKey() public { // Get Alice's nonce - uint256 nonce = users.alice.deleGator.getNonce(uint192(100)); - assertEq(nonce, 1844674407370955161600); + uint256 nonce_ = users.alice.deleGator.getNonce(uint192(100)); + assertEq(nonce_, 1844674407370955161600); } // should allow retrieval of the deposit in the entry point function test_allow_getDeposit() public { // Get Alice's deposit - uint256 deposit = users.alice.deleGator.getDeposit(); - assertEq(deposit, 0); + uint256 deposit_ = users.alice.deleGator.getDeposit(); + assertEq(deposit_, 0); } // should allow retrieval of the entry point @@ -130,35 +129,10 @@ abstract contract DeleGatorTestSuite is BaseTest { assertEq(entryPoint_, address(entryPoint)); } - // should allow Alice to store a Delegation onchain through a UserOp - function test_allow_storeOnchainDelegation() public { - // Create delegation - Delegation memory delegation = Delegation({ - delegate: address(users.bob.addr), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Submit Alice's UserOp - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Get delegation hash - bytes32 delegationHash = EncoderLib._getDelegationHash(delegation); - - // Get stored delegation - bool isOnchain = users.alice.deleGator.isDelegationOnchain(delegationHash); - - // Validate that the delegation is correct - assertTrue(isOnchain); - } - // should allow Alice to enable/disable an offchain Delegation with a Delegation struct function test_allow_updatingOffchainDelegationDisabledStateWithStruct() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -168,94 +142,46 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Get delegation hash - bytes32 delegationHash = EncoderLib._getDelegationHash(delegation); + bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); - PackedUserOperation memory disableUserOp = createAndSignUserOp( + PackedUserOperation memory disableUserOp_ = createAndSignUserOp( users.alice, address(users.alice.deleGator), abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ) ); - PackedUserOperation memory enableUserOp = createAndSignUserOp( - users.alice, - address(users.alice.deleGator), - abi.encodeWithSignature("enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation) - ); - - // check before revoking - bool isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertEq(isDisabled, false); - - // Disable delegation - vm.expectEmit(true, true, true, true); - emit DisabledDelegation(delegationHash, address(users.alice.deleGator), users.bob.addr, delegation); - submitUserOp_Bundler(disableUserOp); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertEq(isDisabled, true); - - // Enable delegation - vm.expectEmit(true, true, true, true); - emit EnabledDelegation(delegationHash, address(users.alice.deleGator), users.bob.addr, delegation); - submitUserOp_Bundler(enableUserOp); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertEq(isDisabled, false); - } - - // should allow Alice to enable/disable an onchain Delegation with a Delegation struct - function test_allow_updatingOnchainDelegationDisabledStateWithStruct() public { - // Create delegation - Delegation memory delegation = Delegation({ - delegate: address(users.bob.addr), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Submit Alice's UserOp - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Get delegation hash - bytes32 delegationHash = EncoderLib._getDelegationHash(delegation); - - PackedUserOperation memory disableUserOp = createAndSignUserOp( + PackedUserOperation memory enableUserOp_ = createAndSignUserOp( users.alice, address(users.alice.deleGator), abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + "enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ) ); - PackedUserOperation memory enableUserOp = createAndSignUserOp( - users.alice, - address(users.alice.deleGator), - abi.encodeWithSignature("enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation) - ); // check before revoking - bool isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertEq(isDisabled, false); + bool isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertEq(isDisabled_, false); // Disable delegation vm.expectEmit(true, true, true, true); - emit DisabledDelegation(delegationHash, address(users.alice.deleGator), users.bob.addr, delegation); - submitUserOp_Bundler(disableUserOp); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertEq(isDisabled, true); + emit DisabledDelegation(delegationHash_, address(users.alice.deleGator), users.bob.addr, delegation_); + submitUserOp_Bundler(disableUserOp_); + isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertEq(isDisabled_, true); // Enable delegation vm.expectEmit(true, true, true, true); - emit EnabledDelegation(delegationHash, address(users.alice.deleGator), users.bob.addr, delegation); - submitUserOp_Bundler(enableUserOp); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertEq(isDisabled, false); + emit EnabledDelegation(delegationHash_, address(users.alice.deleGator), users.bob.addr, delegation_); + submitUserOp_Bundler(enableUserOp_); + isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertEq(isDisabled_, false); } // should not allow Alice to delegate if she is not the delegator function test_notAllow_delegatingForAnotherDelegator() public { // Creating an invalid delegation where Alice is not the delegator. - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.carol.deleGator), delegator: address(users.bob.deleGator), authority: ROOT_AUTHORITY, @@ -264,25 +190,26 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); // Create UserOp - bytes memory userOpCallData = - abi.encodeWithSignature("enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation); + bytes memory userOpCallData_ = abi.encodeWithSignature( + "enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ + ); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData_); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); // Expect a revert event vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegator.selector) + userOpHash_, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegator.selector) ); // Submit the UserOp - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } // should not allow Alice to disable an invalid delegation function test_notAllow_disablingInvalidDelegation() public { - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.carol.deleGator), delegator: address(users.bob.deleGator), authority: ROOT_AUTHORITY, @@ -291,21 +218,21 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); // Create UserOp - bytes memory userOpCallData = abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + bytes memory userOpCallData_ = abi.encodeWithSignature( + "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData_); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); // Expect a revert event vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegator.selector) + userOpHash_, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegator.selector) ); // Submit the UserOp - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } // should not allow using a delegation without a signature @@ -325,46 +252,16 @@ abstract contract DeleGatorTestSuite is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - vm.expectRevert(abi.encodeWithSelector(IDelegationManager.InvalidDelegation.selector)); + vm.expectRevert(abi.encodeWithSelector(IDelegationManager.EmptySignature.selector)); vm.prank(address(users.bob.deleGator)); users.bob.deleGator.redeemDelegation(abi.encode(delegations_), action_); } - // should not allow to delegate already existing delegation - function test_notAllow_alreadyExistingDelegation() public { - // Create delegation - Delegation memory delegation = Delegation({ - delegate: address(users.bob.addr), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Submit Alice's UserOp to delegate - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Create Alice's UserOp (with valid EntryPoint) - bytes memory userOpCallData = abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); - - // Expect a revert event - vm.expectEmit(true, true, false, true, address(entryPoint)); - emit UserOperationRevertReason( - userOpHash, address(users.alice.deleGator), 1, abi.encodeWithSelector(IDelegationManager.AlreadyExists.selector) - ); - - // Submit the UserOp - submitUserOp_Bundler(userOp); - } - // should not allow to enable already enabled delegation function test_notAllow_enableAlreadyEnabledDelegation() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -373,29 +270,29 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Submit Alice's UserOp to delegate - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation_ = signDelegation(users.alice, delegation_); // Create UserOp - bytes memory userOpCallData = - abi.encodeWithSignature("enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation); + bytes memory userOpCallData_ = abi.encodeWithSignature( + "enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ + ); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData_); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); // Expect a revert event vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, address(users.alice.deleGator), 1, abi.encodeWithSelector(IDelegationManager.AlreadyEnabled.selector) + userOpHash_, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.AlreadyEnabled.selector) ); // Submit the UserOp - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } function test_notAllow_disableAlreadyDisabledDelegation() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -404,53 +301,50 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Submit Alice's UserOp to delegate - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation_ = signDelegation(users.alice, delegation_); // Get delegation hash - bytes32 delegationHash = EncoderLib._getDelegationHash(delegation); + bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); // Get stored delegation disabled state - bool isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertFalse(isDisabled); + bool isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertFalse(isDisabled_); // Disable delegation execute_UserOp( users.alice, abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ) ); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertTrue(isDisabled); + isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertTrue(isDisabled_); // Create UserOp - PackedUserOperation memory disableUserOp = createAndSignUserOp( + PackedUserOperation memory disableUserOp_ = createAndSignUserOp( users.alice, address(users.alice.deleGator), abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ) ); - bytes32 userOpHash = entryPoint.getUserOpHash(disableUserOp); - - // Expect a revert event + bytes32 userOpHash_ = entryPoint.getUserOpHash(disableUserOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, address(users.alice.deleGator), 2, abi.encodeWithSelector(IDelegationManager.AlreadyDisabled.selector) + userOpHash_, address(users.alice.deleGator), 1, abi.encodeWithSelector(IDelegationManager.AlreadyDisabled.selector) ); // Submit the UserOp - submitUserOp_Bundler(disableUserOp); + submitUserOp_Bundler(disableUserOp_); } // should allow Alice to disable an offchain Delegation function test_allow_disableOffchainDelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -460,65 +354,65 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Bob's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations, action); + invokeDelegation_UserOp(users.bob, delegations_, action_); // Get intermediate count - uint256 intermediateValue = aliceDeleGatorCounter.count(); + uint256 intermediateValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(intermediateValue, initialValue + 1); + assertEq(intermediateValue_, initialValue_ + 1); execute_UserOp( users.alice, abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ) ); - bytes memory userOpCallData = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action); + bytes memory userOpCallData_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); uint256[] memory signers_ = new uint256[](1); signers_[0] = users.bob.privateKey; - PackedUserOperation memory userOp = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; vm.prank(bundler); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, + userOpHash_, address(users.bob.deleGator), 1, abi.encodeWithSelector(IDelegationManager.CannotUseADisabledDelegation.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased - assertEq(finalValue, intermediateValue); + assertEq(finalValue_, intermediateValue_); } - // should allow Alice to reset a disabled onchain delegation + // should allow Alice to reset a disabled delegation function test_allow_resetDisabledDelegation() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -527,111 +421,60 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Submit Alice's UserOp to delegate - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - // Get delegation hash - bytes32 delegationHash = EncoderLib._getDelegationHash(delegation); + bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); // Get stored delegation disabled state - bool isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertFalse(isDisabled); + bool isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertFalse(isDisabled_); // Disable delegation execute_UserOp( users.alice, abi.encodeWithSignature( - "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation + "disableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ ) ); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertTrue(isDisabled); + isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertTrue(isDisabled_); // Enable delegation execute_UserOp( users.alice, - abi.encodeWithSignature("enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation) + abi.encodeWithSignature( + "enableDelegation((address,address,bytes32,(address,bytes,bytes)[],uint256,bytes))", delegation_ + ) ); - isDisabled = users.alice.deleGator.isDelegationDisabled(delegationHash); - assertFalse(isDisabled); - } - - // should allow anyone to redeem an open Delegation (onchain) - function test_allow_onchainOpenDelegation() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - uint256 updatedValue; - - // Create delegation - Caveat[] memory caveats = new Caveat[](1); - caveats[0] = Caveat({ - args: hex"", - enforcer: address(allowedTargetsEnforcer), - terms: abi.encodePacked(address(aliceDeleGatorCounter)) - }); - Delegation memory delegation = Delegation({ - delegate: ANY_DELEGATE, - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: caveats, - salt: 0, - signature: hex"" - }); - - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Bob's Delegator redeems the delegation - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - invokeDelegation_UserOp(users.bob, delegations, action); - - // Validate that the count has increased by 1 - updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); - initialValue = updatedValue; - - bytes32[] memory delegationHashes = new bytes32[](1); - delegationHashes[0] = EncoderLib._getDelegationHash(delegation); - // Bob redeems the delegation - vm.prank(users.bob.addr); - vm.expectEmit(true, true, true, true, address(delegationManager)); - emit RedeemedDelegation(delegation.delegator, users.bob.addr, delegation); - delegationManager.redeemDelegation(abi.encode(delegations), action); - - // Validate that the count has increased by 1 - updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); + isDisabled_ = users.alice.deleGator.isDelegationDisabled(delegationHash_); + assertFalse(isDisabled_); } - // should emit an event when the action is executed + // should emit an event when the action_ is executed function test_emit_executedActionEvent() public { - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Bob's Delegator redeems the delegation - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Creating a valid action vm.prank(address(entryPoint)); vm.expectEmit(true, true, true, true, address(users.alice.deleGator)); - emit ExecutedAction(action.to, action.value, true, hex""); - users.alice.deleGator.execute(action); + emit ExecutedAction(action_.to, action_.value, true, hex""); + users.alice.deleGator.execute(action_); // Validate that the count has increased by 1 - uint256 updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); + uint256 updatedValue_ = aliceDeleGatorCounter.count(); + assertEq(updatedValue_, initialValue_ + 1); - // Creating a invalid action - action.value = 1; + // Creating a invalid action_ + action_.value = 1; vm.prank(address(entryPoint)); // Expect it to emit a reverted event vm.expectEmit(true, true, true, true, address(users.alice.deleGator)); vm.expectRevert(abi.encodeWithSelector(ExecutionLib.FailedExecutionWithoutReason.selector)); - emit ExecutedAction(action.to, action.value, false, hex""); - users.alice.deleGator.execute(action); + emit ExecutedAction(action_.to, action_.value, false, hex""); + users.alice.deleGator.execute(action_); } // should emit an event when paying the prefund @@ -651,242 +494,108 @@ abstract contract DeleGatorTestSuite is BaseTest { // should allow anyone to redeem an open Delegation (offchain) function test_allow_offchainOpenDelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - uint256 updatedValue; + uint256 initialValue_ = aliceDeleGatorCounter.count(); + uint256 updatedValue_; // Create delegation - Caveat[] memory caveats = new Caveat[](1); - caveats[0] = Caveat({ + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(address(aliceDeleGatorCounter)) }); - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: ANY_DELEGATE, delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, - caveats: caveats, + caveats: caveats_, salt: 0, signature: hex"" }); // Alice signs delegation - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); // Bob's Delegator redeems the delegation - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations, action); + invokeDelegation_UserOp(users.bob, delegations_, action_); // Validate that the count has increased by 1 - updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); - initialValue = updatedValue; + updatedValue_ = aliceDeleGatorCounter.count(); + assertEq(updatedValue_, initialValue_ + 1); + initialValue_ = updatedValue_; // Bob redeems the delegation vm.prank(users.bob.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); - - // Validate that the count has increased by 1 - updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); - } - - // should allow anyone to redelegate an open Delegation (onchain) - function test_allow_onchainOpenDelegationRedelegation() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - uint256 updatedValue; - - // Create & store Alice's delegation - Caveat[] memory caveats = new Caveat[](1); - caveats[0] = Caveat({ - args: hex"", - enforcer: address(allowedTargetsEnforcer), - terms: abi.encodePacked(address(aliceDeleGatorCounter)) - }); - Delegation memory aliceDelegation = Delegation({ - delegate: ANY_DELEGATE, - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: caveats, - salt: 0, - signature: hex"" - }); - bytes32 aliceDelegationHash = EncoderLib._getDelegationHash(aliceDelegation); - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, aliceDelegation)); - - // Create & store Bob's delegation - Delegation memory bobDelegation = Delegation({ - delegate: users.carol.addr, - delegator: address(users.bob.deleGator), - authority: aliceDelegationHash, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - execute_UserOp(users.bob, abi.encodeWithSelector(IDelegationManager.delegate.selector, bobDelegation)); - - // Carol redeems the delegation - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; - - vm.prank(users.carol.addr); - vm.expectEmit(true, true, true, true, address(delegationManager)); - emit RedeemedDelegation(aliceDelegation.delegator, users.carol.addr, bobDelegation); - vm.expectEmit(true, true, true, true, address(delegationManager)); - emit RedeemedDelegation(aliceDelegation.delegator, users.carol.addr, aliceDelegation); - delegationManager.redeemDelegation(abi.encode(delegations), action); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Validate that the count has increased by 1 - updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); + updatedValue_ = aliceDeleGatorCounter.count(); + assertEq(updatedValue_, initialValue_ + 1); } // should allow anyone to redelegate an open Delegation (offchain) function test_allow_offchainOpenDelegationRedelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - uint256 updatedValue; + uint256 initialValue_ = aliceDeleGatorCounter.count(); + uint256 updatedValue_; // Create Alice's open delegation - Caveat[] memory caveats = new Caveat[](1); - caveats[0] = Caveat({ + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(address(aliceDeleGatorCounter)) }); - Delegation memory aliceDelegation = Delegation({ + Delegation memory aliceDelegation_ = Delegation({ delegate: ANY_DELEGATE, delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, - caveats: caveats, + caveats: caveats_, salt: 0, signature: hex"" }); - bytes32 aliceDelegationHash = EncoderLib._getDelegationHash(aliceDelegation); - aliceDelegation = signDelegation(users.alice, aliceDelegation); + bytes32 aliceDelegationHash_ = EncoderLib._getDelegationHash(aliceDelegation_); + aliceDelegation_ = signDelegation(users.alice, aliceDelegation_); // Bob's DeleGator redelegates the open delegation - Delegation memory bobDelegation = Delegation({ + Delegation memory bobDelegation_ = Delegation({ delegate: users.carol.addr, delegator: address(users.bob.deleGator), - authority: aliceDelegationHash, + authority: aliceDelegationHash_, caveats: new Caveat[](0), salt: 0, signature: hex"" }); - bobDelegation = signDelegation(users.bob, bobDelegation); + bobDelegation_ = signDelegation(users.bob, bobDelegation_); // Carol redeems the delegation - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = bobDelegation_; + delegations_[1] = aliceDelegation_; // Carol redeems the delegation vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); - - // Validate that the count has increased by 1 - updatedValue = aliceDeleGatorCounter.count(); - assertEq(updatedValue, initialValue + 1); - } - - // should allow Bob's DeleGator to redeem a Delegation through a UserOp (onchain) - function test_allow_deleGatorInvokeOnchainDelegation() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create delegation - Delegation memory delegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Create Bob's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Execute Bob's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - - invokeDelegation_UserOp(users.bob, delegations, action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); - } - - // should allow Bob to redeem a Delegation with Caveats through a UserOp (onchain) - function test_allow_invokeOnchainDelegationWithCaveats() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create Caveats - Caveat[] memory caveats = new Caveat[](2); - caveats[0] = Caveat({ - args: hex"", - enforcer: address(allowedTargetsEnforcer), - terms: abi.encodePacked(address(aliceDeleGatorCounter)) - }); - caveats[1] = - Caveat({ args: hex"", enforcer: address(allowedMethodsEnforcer), terms: abi.encodePacked(Counter.increment.selector) }); - - // Create delegation - Delegation memory delegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: caveats, - salt: 0, - signature: hex"" - }); - - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Create Bob's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Execute Bob's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - - invokeDelegation_UserOp(users.bob, delegations, action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + updatedValue_ = aliceDeleGatorCounter.count(); + assertEq(updatedValue_, initialValue_ + 1); } // should NOT allow Bob to redeem a delegation with poorly formed data function test_notAllow_invalidRedeemDelegationData() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: users.bob.addr, delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -895,28 +604,27 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); vm.prank(users.bob.addr); vm.expectRevert(); - delegationManager.redeemDelegation(abi.encode("quack"), action); + delegationManager.redeemDelegation(abi.encode("quack"), action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased - assertEq(finalValue, initialValue); + assertEq(finalValue_, initialValue_); } // should not allow call to Implementation's validateUserOp function test_notAllow_callFromNonProxyAddress_ValidateUserOp() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -926,19 +634,19 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Create Alice's UserOp - bytes memory userOpCallData = abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes memory userOpCallData_ = abi.encodeWithSelector(IDelegationManager.enableDelegation.selector, delegation_); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData_); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectRevert(UUPSUpgradeable.UUPSUnauthorizedCallContext.selector); vm.prank(address(entryPoint)); - hybridDeleGatorImpl.validateUserOp(userOp, userOpHash, 0); + hybridDeleGatorImpl.validateUserOp(userOp_, userOpHash_, 0); } // should not allow call to Implementation's IsValidSignature function test_notAllow_callFromNonProxyAddress_IsValidSignature() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -948,58 +656,22 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Create Alice's UserOp - bytes memory userOpCallData = abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes memory userOpCallData_ = abi.encodeWithSelector(IDelegationManager.enableDelegation.selector, delegation_); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData_); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectRevert(UUPSUpgradeable.UUPSUnauthorizedCallContext.selector); vm.prank(address(entryPoint)); - hybridDeleGatorImpl.isValidSignature(userOpHash, userOp.signature); - } - - // should allow Bob to redeem a Delegation through a UserOp (onchain) - function test_allow_eoaInvokeOnchainDelegation() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create delegation - Delegation memory delegation = Delegation({ - delegate: users.bob.addr, - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Create Bob's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Redeem Bob's delegation - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - - vm.prank(users.bob.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + hybridDeleGatorImpl.isValidSignature(userOpHash_, userOp_.signature); } // should allow Bob's DeleGator to redeem a Delegation through a UserOp (offchain) function test_allow_deleGatorInvokeOffchainDelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1009,32 +681,32 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Bob's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations, action); + invokeDelegation_UserOp(users.bob, delegations_, action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_ + 1); } // should allow Bob to redeem a Delegation through a UserOp (offchain) function test_allow_eoaInvokeOffchainDelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: users.bob.addr, delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1044,33 +716,33 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Redeem Bob's delegation - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; vm.prank(users.bob.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_ + 1); } // should allow Bob (EOA) to redelegate a Delegation (offchain) function test_allow_eoaRedelegateOffchainDelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create Alice's delegation to Bob - Delegation memory delegation1 = Delegation({ + Delegation memory delegation1_ = Delegation({ delegate: users.bob.addr, delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1078,49 +750,49 @@ abstract contract DeleGatorTestSuite is BaseTest { salt: 0, signature: hex"" }); - delegation1 = signDelegation(users.alice, delegation1); - bytes32 delegationHash1 = EncoderLib._getDelegationHash(delegation1); + delegation1_ = signDelegation(users.alice, delegation1_); + bytes32 delegationHash1_ = EncoderLib._getDelegationHash(delegation1_); // Create Bob's Delegation to Carol - Delegation memory delegation2 = Delegation({ + Delegation memory delegation2_ = Delegation({ delegate: users.carol.addr, delegator: users.bob.addr, - authority: delegationHash1, + authority: delegationHash1_, caveats: new Caveat[](0), salt: 0, signature: hex"" }); - bytes32 delegationHash2 = EncoderLib._getDelegationHash(delegation2); - bytes32 domainHash = delegationManager.getDomainHash(); - bytes32 typedDataHash = MessageHashUtils.toTypedDataHash(domainHash, delegationHash2); - delegation2.signature = SigningUtilsLib.signHash_EOA(users.bob.privateKey, typedDataHash); + bytes32 delegationHash2_ = EncoderLib._getDelegationHash(delegation2_); + bytes32 domainHash_ = delegationManager.getDomainHash(); + bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(domainHash_, delegationHash2_); + delegation2_.signature = SigningUtilsLib.signHash_EOA(users.bob.privateKey, typedDataHash_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Redeem Carol's delegation - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = delegation2; - delegations[1] = delegation1; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = delegation2_; + delegations_[1] = delegation1_; vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_ + 1); } // should not allow Carol to claim a delegation when EOA signature doesn't match the delegator function test_notAllow_eoaRedelegateOffchainDelegation() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create Alice's delegation to Bob - Delegation memory delegation1 = Delegation({ + Delegation memory delegation1_ = Delegation({ delegate: users.bob.addr, delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1128,191 +800,94 @@ abstract contract DeleGatorTestSuite is BaseTest { salt: 0, signature: hex"" }); - delegation1 = signDelegation(users.alice, delegation1); - bytes32 delegationHash1 = EncoderLib._getDelegationHash(delegation1); + delegation1_ = signDelegation(users.alice, delegation1_); + bytes32 delegationHash1_ = EncoderLib._getDelegationHash(delegation1_); // Create Bob's Delegation to Carol (signed by Dave) - Delegation memory delegation2 = Delegation({ + Delegation memory delegation2_ = Delegation({ delegate: users.carol.addr, delegator: users.bob.addr, - authority: delegationHash1, + authority: delegationHash1_, caveats: new Caveat[](0), salt: 0, signature: hex"" }); - bytes32 delegationHash2 = EncoderLib._getDelegationHash(delegation2); - bytes32 domainHash = delegationManager.getDomainHash(); - bytes32 typedDataHash = MessageHashUtils.toTypedDataHash(domainHash, delegationHash2); - delegation2.signature = SigningUtilsLib.signHash_EOA(users.dave.privateKey, typedDataHash); + bytes32 delegationHash2_ = EncoderLib._getDelegationHash(delegation2_); + bytes32 domainHash_ = delegationManager.getDomainHash(); + bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(domainHash_, delegationHash2_); + delegation2_.signature = SigningUtilsLib.signHash_EOA(users.dave.privateKey, typedDataHash_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Redeem Carol's delegation - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = delegation2; - delegations[1] = delegation1; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = delegation2_; + delegations_[1] = delegation1_; vm.prank(users.carol.addr); vm.expectRevert(abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector)); - delegationManager.redeemDelegation(abi.encode(delegations), action); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Get final count // Validate that the count has increased by 1 - uint256 finalValue = aliceDeleGatorCounter.count(); - assertEq(finalValue, initialValue); + uint256 finalValue_ = aliceDeleGatorCounter.count(); + assertEq(finalValue_, initialValue_); } // should allow Bob to redeem a Delegation with Caveats through a UserOp (offchain) function test_allow_invokeOffchainDelegationWithCaveats() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create Caveats - Caveat[] memory caveats = new Caveat[](2); - caveats[0] = Caveat({ + Caveat[] memory caveats_ = new Caveat[](2); + caveats_[0] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(address(aliceDeleGatorCounter)) }); - caveats[1] = + caveats_[1] = Caveat({ args: hex"", enforcer: address(allowedMethodsEnforcer), terms: abi.encodePacked(Counter.increment.selector) }); // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, - caveats: caveats, + caveats: caveats_, salt: 0, signature: hex"" }); // Alice signs delegation - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Bob's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - - invokeDelegation_UserOp(users.bob, delegations, action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); - } - - // should allow Carol to redeem a Delegation through a UserOp (onchain & offchain) - function test_allow_invokeCombinedDelegationChain() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create Alice's delegation to Bob - Delegation memory aliceDelegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, aliceDelegation)); - - // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ - delegate: address(users.carol.deleGator), - delegator: address(users.bob.deleGator), - authority: EncoderLib._getDelegationHash(aliceDelegation), - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Sign Bob's delegation - Delegation memory signedBobDelegation = signDelegation(users.bob, bobDelegation); - - // Create Carol's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Execute Carol's UserOp - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = signedBobDelegation; - delegations[1] = aliceDelegation; - - invokeDelegation_UserOp(users.carol, delegations, action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); - } - - // should allow Carol's DeleGator to claim an onchain redelegation from Bob - function test_allow_chainOfOnchainDelegationToDeleGators() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create Alice's delegation to Bob - Delegation memory aliceDelegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, aliceDelegation)); - - // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ - delegate: address(users.carol.deleGator), - delegator: address(users.bob.deleGator), - authority: EncoderLib._getDelegationHash(aliceDelegation), - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.bob, abi.encodeWithSelector(IDelegationManager.delegate.selector, bobDelegation)); - - // Create Carol's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - invokeDelegation_UserOp(users.carol, delegations, action); + invokeDelegation_UserOp(users.bob, delegations_, action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_ + 1); } // should allow Carol's DeleGator to claim an offchain redelegation from Bob function test_allow_chainOfOffchainDelegationToDeleGators() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory aliceDelegation = Delegation({ + Delegation memory aliceDelegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1322,46 +897,46 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - aliceDelegation = signDelegation(users.alice, aliceDelegation); + aliceDelegation_ = signDelegation(users.alice, aliceDelegation_); // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ + Delegation memory bobDelegation_ = Delegation({ delegate: address(users.carol.deleGator), delegator: address(users.bob.deleGator), - authority: EncoderLib._getDelegationHash(aliceDelegation), + authority: EncoderLib._getDelegationHash(aliceDelegation_), caveats: new Caveat[](0), salt: 0, signature: hex"" }); // Sign Bob's delegation - bobDelegation = signDelegation(users.bob, bobDelegation); + bobDelegation_ = signDelegation(users.bob, bobDelegation_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Carol's UserOp - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = bobDelegation_; + delegations_[1] = aliceDelegation_; - invokeDelegation_UserOp(users.carol, delegations, action); + invokeDelegation_UserOp(users.carol, delegations_, action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_ + 1); } // should not allow Carol to redelegate a delegation to Bob function test_notAllow_chainOfOffchainDelegationToDeleGators() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation from Alice to Bob - Delegation memory aliceDelegation = Delegation({ + Delegation memory aliceDelegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1371,64 +946,64 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - aliceDelegation = signDelegation(users.alice, aliceDelegation); + aliceDelegation_ = signDelegation(users.alice, aliceDelegation_); // Create Carol's delegation to Dave - Delegation memory carolDelegation = Delegation({ + Delegation memory carolDelegation_ = Delegation({ delegate: address(users.dave.deleGator), delegator: address(users.carol.deleGator), - authority: EncoderLib._getDelegationHash(aliceDelegation), + authority: EncoderLib._getDelegationHash(aliceDelegation_), caveats: new Caveat[](0), salt: 0, signature: hex"" }); // Sign Carol's delegation - carolDelegation = signDelegation(users.carol, carolDelegation); + carolDelegation_ = signDelegation(users.carol, carolDelegation_); // Create Dave's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Dave's UserOp - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = carolDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = carolDelegation_; + delegations_[1] = aliceDelegation_; - PackedUserOperation memory userOp = createAndSignUserOp( + PackedUserOperation memory userOp_ = createAndSignUserOp( users.dave, address(users.dave.deleGator), - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action) + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_) ); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; vm.prank(bundler); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); // Expect it to emit a reverted event vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, address(users.dave.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegate.selector) + userOpHash_, address(users.dave.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegate.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased - assertEq(finalValue, initialValue); + assertEq(finalValue_, initialValue_); } // should shortcircuit Carol's DeleGator's delegation redemption to increase Alice's DeleGator's Counter function test_executesFirstRootAuthorityFound() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory aliceDelegation = Delegation({ + Delegation memory aliceDelegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1438,10 +1013,10 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - aliceDelegation = signDelegation(users.alice, aliceDelegation); + aliceDelegation_ = signDelegation(users.alice, aliceDelegation_); // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ + Delegation memory bobDelegation_ = Delegation({ delegate: address(users.carol.deleGator), delegator: address(users.bob.deleGator), authority: ROOT_AUTHORITY, @@ -1451,82 +1026,33 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Sign Bob's delegation - bobDelegation = signDelegation(users.bob, bobDelegation); + bobDelegation_ = signDelegation(users.bob, bobDelegation_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Carol's UserOp - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = bobDelegation_; + delegations_[1] = aliceDelegation_; - invokeDelegation_UserOp(users.carol, delegations, action); + invokeDelegation_UserOp(users.carol, delegations_, action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased by 1 - assertEq(finalValue, initialValue); - } - - // should allow Carol to claim an onchain redelegation from Bob - function test_allow_chainOfOnchainDelegationToEoa() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create Alice's delegation to Bob - Delegation memory aliceDelegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, aliceDelegation)); - - // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ - delegate: users.carol.addr, - delegator: address(users.bob.deleGator), - authority: EncoderLib._getDelegationHash(aliceDelegation), - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.bob, abi.encodeWithSelector(IDelegationManager.delegate.selector, bobDelegation)); - - // Create Carol's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; - - vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_); } // should allow Carol to claim an offchain redelegation from Bob function test_allow_chainOfOffchainDelegationToEoa() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory aliceDelegation = Delegation({ + Delegation memory aliceDelegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1536,69 +1062,69 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Alice signs delegation - aliceDelegation = signDelegation(users.alice, aliceDelegation); + aliceDelegation_ = signDelegation(users.alice, aliceDelegation_); // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ + Delegation memory bobDelegation_ = Delegation({ delegate: users.carol.addr, delegator: address(users.bob.deleGator), - authority: EncoderLib._getDelegationHash(aliceDelegation), + authority: EncoderLib._getDelegationHash(aliceDelegation_), caveats: new Caveat[](0), salt: 0, signature: hex"" }); // Sign Bob's delegation - bobDelegation = signDelegation(users.bob, bobDelegation); + bobDelegation_ = signDelegation(users.bob, bobDelegation_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Carol's UserOp - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = bobDelegation_; + delegations_[1] = aliceDelegation_; vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations), action); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 - assertEq(finalValue, initialValue + 1); + assertEq(finalValue_, initialValue_ + 1); } - // should allow Alice to execute multiple actions in a single UserOp + // should allow Alice to execute multiple actions_ in a single UserOp function test_allow_multiAction_UserOp() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create actions - Action[] memory actions = new Action[](2); - actions[0] = + // Create actions_ + Action[] memory actions_ = new Action[](2); + actions_[0] = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - actions[1] = + actions_[1] = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Actions - executeBatch_UserOp(users.alice, actions); + executeBatch_UserOp(users.alice, actions_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); - // Validate that the delegations were stored - assertEq(finalValue, initialValue + 2); + // Validate that the delegations_ were worked + assertEq(finalValue_, initialValue_ + 2); } // should not allow to execute empty Actions function test_notAllow_emptyAction_UserOp() public { //Create Actions - Action[] memory actions = new Action[](0); + Action[] memory actions_ = new Action[](0); - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.executeBatch.selector, actions); - PackedUserOperation memory userOp_ = createUserOp(address(users.alice.deleGator), userOpCallData_); + bytes memory userOpCallData__ = abi.encodeWithSelector(IDeleGatorCoreFull.executeBatch.selector, actions_); + PackedUserOperation memory userOp_ = createUserOp(address(users.alice.deleGator), userOpCallData__); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(users.alice, userOpHash_.toEthSignedMessageHash()); @@ -1613,57 +1139,13 @@ abstract contract DeleGatorTestSuite is BaseTest { entryPoint.handleOps(userOps_, payable(bundler)); } - // should allow Bob to execute multiple actions that redeem delegations in a single UserOp - function test_allow_multiActionDelegationClaim_Onchain_UserOp() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create Alice's delegation to Bob - Delegation memory delegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Create onchain action Action - Action memory incrementAction = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Invoke delegation calldata - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - - bytes memory invokeDelegationCalldata = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), incrementAction); - - // Create invoke delegation Actions - Action[] memory redemptionActions = new Action[](2); - redemptionActions[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata }); - redemptionActions[1] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata }); - - // Execute delegations - executeBatch_UserOp(users.bob, redemptionActions); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the counts were increased - assertEq(finalValue, initialValue + 2); - } - - // should allow Bob to execute multiple actions that redeem delegations in a single UserOp + // should allow Bob to execute multiple actions_ that redeem delegations_ in a single UserOp (offchain) function test_allow_multiActionDelegationClaim_Offchain_UserOp() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create Alice's delegation to Bob - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1673,39 +1155,39 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Sign delegation - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); - // Create onchain action Action - Action memory incrementAction = + // Create Action + Action memory incrementAction_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Invoke delegation calldata - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - bytes memory invokeDelegationCalldata = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), incrementAction); + bytes memory invokeDelegationCalldata_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), incrementAction_); // Create invoke delegation Actions - Action[] memory redemptionActions = new Action[](2); - redemptionActions[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata }); - redemptionActions[1] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata }); + Action[] memory redemptionActions_ = new Action[](2); + redemptionActions_[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata_ }); + redemptionActions_[1] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata_ }); - // Execute delegations - executeBatch_UserOp(users.bob, redemptionActions); + // Execute delegations_ + executeBatch_UserOp(users.bob, redemptionActions_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the counts were increased - assertEq(finalValue, initialValue + 2); + assertEq(finalValue_, initialValue_ + 2); } - // should allow Alice to execute a combination of actions through a single UserOp + // should allow Alice to execute a combination of actions_ through a single UserOp function test_allow_multiActionCombination_UserOp() public { // Get DeleGator's Counter's initial count - uint256 initialValueAlice = aliceDeleGatorCounter.count(); - uint256 initialValueBob = bobDeleGatorCounter.count(); + uint256 initialValueAlice_ = aliceDeleGatorCounter.count(); + uint256 initialValueBob_ = bobDeleGatorCounter.count(); // Create Alice's delegation to Bob Delegation memory delegation = Delegation({ @@ -1721,31 +1203,31 @@ abstract contract DeleGatorTestSuite is BaseTest { delegation = signDelegation(users.alice, delegation); // Invoke delegation calldata - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation; - bytes memory invokeDelegationCalldata = abi.encodeWithSelector( + bytes memory invokeDelegationCalldata_ = abi.encodeWithSelector( IDeleGatorCoreFull.redeemDelegation.selector, - abi.encode(delegations), + abi.encode(delegations_), Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }) ); // Create invoke delegation Actions - Action[] memory redemptionActions = new Action[](2); - redemptionActions[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata }); - redemptionActions[1] = + Action[] memory redemptionActions_ = new Action[](2); + redemptionActions_[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata_ }); + redemptionActions_[1] = Action({ to: address(bobDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - // Execute delegations - executeBatch_UserOp(users.bob, redemptionActions); + // Execute delegations_ + executeBatch_UserOp(users.bob, redemptionActions_); // Get final count - uint256 finalValueAlice = aliceDeleGatorCounter.count(); - uint256 finalValueBob = bobDeleGatorCounter.count(); + uint256 finalValueAlice_ = aliceDeleGatorCounter.count(); + uint256 finalValueBob_ = bobDeleGatorCounter.count(); // Validate that the counts were increased - assertEq(finalValueAlice, initialValueAlice + 1); - assertEq(finalValueBob, initialValueBob + 1); + assertEq(finalValueAlice_, initialValueAlice_ + 1); + assertEq(finalValueBob_, initialValueBob_ + 1); } ////////////////////////////// Invalid cases ////////////////////////////// @@ -1753,31 +1235,31 @@ abstract contract DeleGatorTestSuite is BaseTest { // should not allow a second Action to execute if the first Action fails function test_notAllow_multiActionUserOp() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValueAlice = aliceDeleGatorCounter.count(); - uint256 initialValueBob = bobDeleGatorCounter.count(); + uint256 initialValueAlice_ = aliceDeleGatorCounter.count(); + uint256 initialValueBob_ = bobDeleGatorCounter.count(); - // Create actions, incorrectly incrementing Bob's Counter first - Action[] memory actions = new Action[](2); - actions[0] = + // Create actions_, incorrectly incrementing Bob's Counter first + Action[] memory actions_ = new Action[](2); + actions_[0] = Action({ to: address(bobDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - actions[1] = + actions_[1] = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - // Execute actions - executeBatch_UserOp(users.alice, actions); + // Execute actions_ + executeBatch_UserOp(users.alice, actions_); // Get final count - uint256 finalValueAlice = aliceDeleGatorCounter.count(); - uint256 finalValueBob = bobDeleGatorCounter.count(); + uint256 finalValueAlice_ = aliceDeleGatorCounter.count(); + uint256 finalValueBob_ = bobDeleGatorCounter.count(); // Validate that the counts were not increased - assertEq(finalValueAlice, initialValueAlice); - assertEq(finalValueBob, initialValueBob); + assertEq(finalValueAlice_, initialValueAlice_); + assertEq(finalValueBob_, initialValueBob_); } // should revert without reason and catch it function test_executionRevertsWithoutReason() public { - // Invalid action, sending ETH to a contract that can't receive it. + // Invalid action_, sending ETH to a contract that can't receive it. Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 1, data: hex"" }); vm.prank(address(delegationManager)); @@ -1787,48 +1269,13 @@ abstract contract DeleGatorTestSuite is BaseTest { users.alice.deleGator.executeDelegatedAction(action_); } - // should NOT allow Carol to redeem a delegation to Bob through a UserOp (onchain) - function test_notAllow_invokeOnchainDelegationToAnotherUser() public { - // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); - - // Create Alice's delegation to Bob - Delegation memory delegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation onchain - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Create Carol's action - Action memory action = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Execute Carol's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; - - invokeDelegation_UserOp(users.carol, delegations, action); - - // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); - - // Validate that the count has NOT increased by 1 - assertEq(finalValue, initialValue); - } - // should NOT allow Carol to redeem a delegation to Bob through a UserOp (offchain) function test_notAllow_invokeOffchainDelegationToAnotherUser() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create Alice's delegation to Bob - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1838,29 +1285,29 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Sign Alice's delegation to Bob - delegation = signDelegation(users.alice, delegation); + delegation_ = signDelegation(users.alice, delegation_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Execute Carol's UserOp - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - invokeDelegation_UserOp(users.carol, delegations, action); + invokeDelegation_UserOp(users.carol, delegations_, action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has NOT increased by 1 - assertEq(finalValue, initialValue); + assertEq(finalValue_, initialValue_); } // should NOT allow a UserOp to be submitted to an invalid EntryPoint function test_notAllow_invalidEntryPoint() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -1870,14 +1317,14 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Create a new EntryPoint - EntryPoint newEntryPoint = new EntryPoint(); + EntryPoint newEntryPoint_ = new EntryPoint(); // Create Alice's UserOp (with valid EntryPoint) - bytes memory userOpCallData = abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation); - PackedUserOperation memory userOp = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData); + bytes memory userOpCallData_ = abi.encodeWithSelector(IDelegationManager.enableDelegation.selector, delegation_); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(users.alice.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; // Submit the UserOp through the Bundler vm.prank(bundler); @@ -1890,11 +1337,11 @@ abstract contract DeleGatorTestSuite is BaseTest { abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPoint.selector) ) ); - newEntryPoint.handleOps(userOps, bundler); + newEntryPoint_.handleOps(userOps_, bundler); // Create Alice's UserOp (with invalid EntryPoint) - userOp = createUserOp(address(users.alice.deleGator), userOpCallData); - userOp = signUserOp(users.alice, userOp, newEntryPoint); + userOp_ = createUserOp(address(users.alice.deleGator), userOpCallData_); + userOp_ = signUserOp(users.alice, userOp_, newEntryPoint_); // Submit the UserOp through the Bundler vm.prank(bundler); @@ -1907,117 +1354,94 @@ abstract contract DeleGatorTestSuite is BaseTest { abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPoint.selector) ) ); - newEntryPoint.handleOps(userOps, bundler); + newEntryPoint_.handleOps(userOps_, bundler); } // should NOT allow a UserOp with an invalid signature function test_notAllow_invalidUserOpSignature() public { - // Create action - Action memory action = + // Create action_ + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Create Alice's UserOp - bytes memory userOpCallData = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action); - PackedUserOperation memory userOp = createUserOp(address(users.alice.deleGator), userOpCallData, hex""); + bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_); + PackedUserOperation memory userOp_ = createUserOp(address(users.alice.deleGator), userOpCallData_, hex""); // Bob signs UserOp - userOp = signUserOp(users.bob, userOp); + userOp_ = signUserOp(users.bob, userOp_); // Submit the UserOp through the Bundler // the signature of the user operation.) // (AA24 signature error = The validateUserOp function of the smart account rejected vm.expectRevert(abi.encodeWithSelector(IEntryPoint.FailedOp.selector, 0, "AA24 signature error")); - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } // should NOT allow a UserOp with a reused nonce function test_notAllow_nonceReuse() public { - // Create action - Action memory action = + // Create action_ + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Create and Sign Alice's UserOp - PackedUserOperation memory userOp = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action) + PackedUserOperation memory userOp_ = createAndSignUserOp( + users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) ); // Submit the UserOp through the Bundler - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); // Submit the UserOp through the Bundler again vm.expectRevert(abi.encodeWithSelector(IEntryPoint.FailedOp.selector, 0, "AA25 invalid account nonce")); - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } ////////////////////////////// EVENTS Emission ////////////////////////////// - // should not allow an invalid delegator to delegate - function test_event_storeDelegation() public { - Delegation memory delegation = Delegation({ - delegate: address(users.bob.addr), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - bytes32 delegationHash = EncoderLib._getDelegationHash(delegation); - - PackedUserOperation memory userOp = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation) - ); - - vm.expectEmit(true, false, false, true); - emit Delegated(delegationHash, address(users.alice.deleGator), address(users.bob.addr), delegation); - - submitUserOp_Bundler(userOp); - } - function test_event_Deposited() public { - Action memory action = Action({ + Action memory action_ = Action({ to: address(users.alice.deleGator), value: 1 ether, data: abi.encodeWithSelector(IDeleGatorCoreFull.addDeposit.selector) }); - PackedUserOperation memory userOp = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action) + PackedUserOperation memory userOp_ = createAndSignUserOp( + users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) ); vm.expectEmit(true, false, false, true); emit Deposited(address(users.alice.deleGator), 1 ether); - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } function test_allow_withdrawDeposit() public { - Action memory action = Action({ + Action memory action_ = Action({ to: address(users.alice.deleGator), value: 1 ether, data: abi.encodeWithSelector(IDeleGatorCoreFull.addDeposit.selector) }); - PackedUserOperation memory userOp = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action) + PackedUserOperation memory userOp_ = createAndSignUserOp( + users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) ); - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); - action = Action({ + action_ = Action({ to: address(users.alice.deleGator), value: 0 ether, data: abi.encodeWithSelector(IDeleGatorCoreFull.withdrawDeposit.selector, address(users.alice.addr), 0.5 ether) }); - userOp = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action) + userOp_ = createAndSignUserOp( + users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) ); vm.expectEmit(true, false, false, true); emit Withdrawn(address(users.alice.deleGator), address(users.alice.addr), 0.5 ether); - submitUserOp_Bundler(userOp); + submitUserOp_Bundler(userOp_); } // test Error @@ -2025,7 +1449,7 @@ abstract contract DeleGatorTestSuite is BaseTest { // Should revert if Alice tries to delegate carol's delegation function test_error_InvalidDelegator() public { // carol create delegation for bob - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.addr), delegator: address(users.carol.deleGator), authority: ROOT_AUTHORITY, @@ -2034,31 +1458,32 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // bob's action - PackedUserOperation memory userOp = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation) + PackedUserOperation memory userOp_ = createAndSignUserOp( + users.alice, + address(users.alice.deleGator), + abi.encodeWithSelector(IDelegationManager.enableDelegation.selector, delegation_) ); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; vm.prank(bundler); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); emit UserOperationRevertReason( - userOpHash, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegator.selector) + userOpHash_, address(users.alice.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegator.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); } // Should revert if there is no valid root authority function test_error_InvalidRootAuthority() public { // Get Alice's DeleGator's Counter's initial count - uint256 initialValue = aliceDeleGatorCounter.count(); + uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: users.bob.addr, delegator: address(users.alice.deleGator), authority: 0x0, @@ -2068,31 +1493,31 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); // Redeem Bob's delegation - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; vm.prank(users.bob.addr); vm.expectRevert(); - delegationManager.redeemDelegation(abi.encode(delegations), action); + delegationManager.redeemDelegation(abi.encode(delegations_), action_); // Get final count - uint256 finalValue = aliceDeleGatorCounter.count(); + uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased by 1 - assertEq(finalValue, initialValue); + assertEq(finalValue_, initialValue_); } - // Should revert if user tries to redeem a delegation without providing delegations + // Should revert if user tries to redeem a delegation without providing delegations_ function test_error_NoDelegationsProvided() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -2101,42 +1526,41 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](0); + Delegation[] memory delegations_ = new Delegation[](0); - // creating UserOpCallData - bytes memory userOpCallData = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action); + // creating userOpCallData_ + bytes memory userOpCallData_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); - PackedUserOperation memory userOp = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; // prank from bundler vm.prank(bundler); // get User Operation hash - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); // expected error emit UserOperationRevertReason( - userOpHash, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.NoDelegationsProvided.selector) + userOpHash_, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.NoDelegationsProvided.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); } // Should revert if the caller is not the delegate function test_error_InvalidDelegate() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -2145,44 +1569,43 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation_ = signDelegation(users.alice, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; // create user operation calldata for invokeDelegation - bytes memory userOpCallData = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action); + bytes memory userOpCallData_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); - PackedUserOperation memory userOp = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; // prank from bundler vm.prank(bundler); // get UserOperation hash - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); - // expect an event containing InvalidDelegation error + // expect an event containing EmptySignature error emit UserOperationRevertReason( - userOpHash, address(users.carol.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegate.selector) + userOpHash_, address(users.carol.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidDelegate.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); } // Should revert if a UserOp signature is invalid function test_error_InvalidSignature() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -2192,46 +1615,46 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Sign Alice's delegation with Carol's private key - delegation = signDelegation(users.carol, delegation); + delegation_ = signDelegation(users.carol, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - // signing the userOp from bob + // signing the userOp_ from bob uint256[] memory signers_ = new uint256[](1); signers_[0] = users.bob.privateKey; - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; - bytes memory userOpCallData = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action); + bytes memory userOpCallData_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); - PackedUserOperation memory userOp = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; // prank from bundler vm.prank(bundler); // get User Operation hash - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); // expect an event containing InvalidSignature error emit UserOperationRevertReason( - userOpHash, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector) + userOpHash_, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); } // Should revert if the delegation signature is from an invalid signer function test_error_InvalidSigner() public { // Create delegation - Delegation memory delegation = Delegation({ + Delegation memory delegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -2241,58 +1664,58 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Carol signs the delegation using Alice's domain hash - delegation = signDelegation(users.carol, delegation); + delegation_ = signDelegation(users.carol, delegation_); // Create Bob's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](1); - delegations[0] = delegation; + Delegation[] memory delegations_ = new Delegation[](1); + delegations_[0] = delegation_; // create user operation calldata for invokeDelegation - bytes memory userOpCallData = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action); + bytes memory userOpCallData_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); // create and sign user operation with Bob - PackedUserOperation memory userOp = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; vm.prank(bundler); // get User Operation hash - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(true, true, false, true, address(entryPoint)); // expect an event containing InvalidDelegationSignature error emit UserOperationRevertReason( - userOpHash, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector) + userOpHash_, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); } // Should revert if executeDelegatedAction is called from an address other than the DelegationManager function test_notAllow_notDelegationManager() public { - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotDelegationManager.selector)); - users.alice.deleGator.executeDelegatedAction(action); + users.alice.deleGator.executeDelegatedAction(action_); } // Should revert if execute is called from an address other than the EntryPoint function test_notAllow_notEntryPoint() public { - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPoint.selector)); - users.alice.deleGator.execute(action); + users.alice.deleGator.execute(action_); } // Should revert if the delegation chain contains invalid authority function test_error_InvalidAuthority() public { // Create Alice's delegation to Bob - Delegation memory aliceDelegation = Delegation({ + Delegation memory aliceDelegation_ = Delegation({ delegate: address(users.bob.deleGator), delegator: address(users.alice.deleGator), authority: ROOT_AUTHORITY, @@ -2301,11 +1724,11 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - // Store delegation onchain - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, aliceDelegation)); + // Sign Alice's delegation to Bob + aliceDelegation_ = signDelegation(users.alice, aliceDelegation_); //create invalid delegation - Delegation memory invalidDelegation = Delegation({ + Delegation memory invalidDelegation_ = Delegation({ delegate: address(users.carol.addr), delegator: address(users.bob.deleGator), authority: ROOT_AUTHORITY, @@ -2315,44 +1738,43 @@ abstract contract DeleGatorTestSuite is BaseTest { }); // Create Bob's delegation to Carol - Delegation memory bobDelegation = Delegation({ + Delegation memory bobDelegation_ = Delegation({ delegate: address(users.carol.deleGator), delegator: address(users.bob.deleGator), - authority: EncoderLib._getDelegationHash(invalidDelegation), + authority: EncoderLib._getDelegationHash(invalidDelegation_), caveats: new Caveat[](0), salt: 0, signature: hex"" }); - // Store delegation onchain - execute_UserOp(users.bob, abi.encodeWithSelector(IDelegationManager.delegate.selector, bobDelegation)); + bobDelegation_ = signDelegation(users.bob, bobDelegation_); // Create Carol's action - Action memory action = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Delegation[] memory delegations = new Delegation[](2); - delegations[0] = bobDelegation; - delegations[1] = aliceDelegation; + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[0] = bobDelegation_; + delegations_[1] = aliceDelegation_; // create user operation calldata for invokeDelegation - bytes memory userOpCallData = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations), action); + bytes memory userOpCallData_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); - PackedUserOperation memory userOp = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData); + PackedUserOperation memory userOp_ = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData_); - PackedUserOperation[] memory userOps = new PackedUserOperation[](1); - userOps[0] = userOp; + PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); + userOps_[0] = userOp_; vm.prank(bundler); - bytes32 userOpHash = entryPoint.getUserOpHash(userOp); + bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); vm.expectEmit(address(entryPoint)); // expect an event containing InvalidAuthority error emit UserOperationRevertReason( - userOpHash, address(users.carol.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidAuthority.selector) + userOpHash_, address(users.carol.deleGator), 0, abi.encodeWithSelector(IDelegationManager.InvalidAuthority.selector) ); - entryPoint.handleOps(userOps, bundler); + entryPoint.handleOps(userOps_, bundler); } } diff --git a/test/HybridDeleGatorTest.t.sol b/test/HybridDeleGatorTest.t.sol index 8d767a5..fffc97d 100644 --- a/test/HybridDeleGatorTest.t.sol +++ b/test/HybridDeleGatorTest.t.sol @@ -48,7 +48,6 @@ contract HybridDeleGator_Test is BaseTest { ////////////////////////////// Errors ////////////////////////////// - error AlreadyExists(bytes32 keyIdHash, string keyId); error InvalidKey(); error KeyDoesNotExist(bytes32 keyIdHash); error CannotRemoveLastKey(); @@ -620,54 +619,6 @@ contract HybridDeleGator_Test is BaseTest { assertEq(users.bob.addr, onlyEoaHybridDeleGator.owner()); } - // A delegate replacing ALL of the existing keys (passkeys and EOA) in a single transaction onchain - function test_allow_replaceEOAWithEOAAndP256WithOnchainDelegation() public { - // Alice is the EOA owner - assertEq(users.alice.addr, aliceDeleGator.owner()); - - // Compute Bob's P256 keys - string[] memory keyIds_ = new string[](1); - uint256[] memory xValues_ = new uint256[](1); - uint256[] memory yValues_ = new uint256[](1); - keyIds_[0] = users.bob.name; - xValues_[0] = users.bob.x; - yValues_[0] = users.bob.y; - - // Create the action that would be executed - Action memory action_ = Action({ - to: address(aliceDeleGator), - value: 0, - data: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, users.bob.addr, keyIds_, xValues_, yValues_) - }); - - Caveat[] memory caveats_ = new Caveat[](0); - Delegation memory delegation_ = Delegation({ - delegate: address(bobDeleGator), - delegator: address(aliceDeleGator), - authority: ROOT_AUTHORITY, - caveats: caveats_, - salt: 0, - signature: hex"" - }); - - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); - - // Execute Bob's UserOp - Delegation[] memory delegations_ = new Delegation[](1); - delegations_[0] = delegation_; - - invokeDelegation_UserOp(users.bob, delegations_, action_); - - // Bob is the EOA owner now - (uint256 x__, uint256 y__) = aliceDeleGator.getKey(users.bob.name); - assertEq(users.bob.x, x__); - assertEq(users.bob.y, y__); - - // Bob is the EOA owner - assertEq(users.bob.addr, aliceDeleGator.owner()); - } - // A delegate replacing ALL of the existing keys (passkeys and EOA) in a single transaction offchain function test_allow_replaceEOAWithEOAAndP256WithOffchainDelegation() public { // Alice is the EOA owner diff --git a/test/InviteTest.t.sol b/test/InviteTest.t.sol index 5f5dfc2..9db5d8f 100644 --- a/test/InviteTest.t.sol +++ b/test/InviteTest.t.sol @@ -10,7 +10,7 @@ import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { Counter } from "./utils/Counter.t.sol"; import { MultiSigDeleGator } from "../src/MultiSigDeleGator.sol"; import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; -import { SimpleFactory } from "./utils/SimpleFactory.sol"; +import { SimpleFactory } from "../src/utils/SimpleFactory.sol"; import { AllowedTargetsEnforcer } from "../src/enforcers/AllowedTargetsEnforcer.sol"; import { AllowedMethodsEnforcer } from "../src/enforcers/AllowedMethodsEnforcer.sol"; diff --git a/test/MultiSigDeleGatorTest.t.sol b/test/MultiSigDeleGatorTest.t.sol index 162b5ad..7693f54 100644 --- a/test/MultiSigDeleGatorTest.t.sol +++ b/test/MultiSigDeleGatorTest.t.sol @@ -18,8 +18,7 @@ import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; import { Counter } from "./utils/Counter.t.sol"; -import { SimpleFactory } from "./utils/SimpleFactory.sol"; -import "forge-std/Test.sol"; +import { SimpleFactory } from "../src/utils/SimpleFactory.sol"; /** * @title Multi Signature DeleGator Implementation Test @@ -146,45 +145,6 @@ contract MultiSigDeleGatorTest is BaseTest { ////////////////////// Redeeming delegations ////////////////////// - // should allow Dave to redeem a Delegation through a UserOp when there's multiple signers (onchain) - function test_allow_invokeOnchainDelegationWithMultipleSigners() public { - // Get sharedDeleGator's Counter's initial count - uint256 initialValue_ = sharedDeleGatorCounter.count(); - - // Create delegation - Delegation memory delegation_ = Delegation({ - delegate: address(users.dave.deleGator), - delegator: address(sharedDeleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - // Store delegation - PackedUserOperation memory userOp_ = - createUserOp(address(sharedDeleGator), abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); - bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); - userOp_.signature = SigningUtilsLib.signHash_MultiSig(sharedDeleGatorPrivateKeys, userOpHash_.toEthSignedMessageHash()); - submitUserOp_Bundler(userOp_); - - // Create Dave's action - Action memory action_ = - Action({ to: address(sharedDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Execute Dave's UserOp - Delegation[] memory delegations_ = new Delegation[](1); - delegations_[0] = delegation_; - - invokeDelegation_UserOp(users.dave, delegations_, action_); - - // Get final count - uint256 finalValue_ = sharedDeleGatorCounter.count(); - - // Validate that the count has increased by 1 - assertEq(finalValue_, initialValue_ + 1); - } - // should allow Dave to redeem a Delegation through a UserOp when there are multiple signers (offchain) function test_allow_invokeOffchainDelegationWithMultipleSigners() public { // Get sharedDeleGator's Counter's initial count diff --git a/test/enforcers/AllowedCalldataEnforcer.t.sol b/test/enforcers/AllowedCalldataEnforcer.t.sol index 1b5f32d..0aa5725 100644 --- a/test/enforcers/AllowedCalldataEnforcer.t.sol +++ b/test/enforcers/AllowedCalldataEnforcer.t.sol @@ -207,8 +207,8 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); @@ -253,8 +253,8 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/AllowedMethodsEnforcer.t.sol b/test/enforcers/AllowedMethodsEnforcer.t.sol index ecbab60..d32dc90 100644 --- a/test/enforcers/AllowedMethodsEnforcer.t.sol +++ b/test/enforcers/AllowedMethodsEnforcer.t.sol @@ -124,8 +124,8 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); @@ -168,8 +168,8 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/AllowedTargetsEnforcer.t.sol b/test/enforcers/AllowedTargetsEnforcer.t.sol index 04281b6..76304c0 100644 --- a/test/enforcers/AllowedTargetsEnforcer.t.sol +++ b/test/enforcers/AllowedTargetsEnforcer.t.sol @@ -120,8 +120,8 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); @@ -168,8 +168,8 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/BlockNumberEnforcer.t.sol b/test/enforcers/BlockNumberEnforcer.t.sol index 5416f07..1a4cf64 100644 --- a/test/enforcers/BlockNumberEnforcer.t.sol +++ b/test/enforcers/BlockNumberEnforcer.t.sol @@ -155,8 +155,7 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + delegation = signDelegation(users.alice, delegation); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/DeployedEnforcer.t.sol b/test/enforcers/DeployedEnforcer.t.sol index d22e0da..b642789 100644 --- a/test/enforcers/DeployedEnforcer.t.sol +++ b/test/enforcers/DeployedEnforcer.t.sol @@ -224,8 +224,8 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + + delegation = signDelegation(users.alice, delegation); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/ERC20TransferAmountEnforcer.t.sol b/test/enforcers/ERC20TransferAmountEnforcer.t.sol index 2481624..be52f45 100644 --- a/test/enforcers/ERC20TransferAmountEnforcer.t.sol +++ b/test/enforcers/ERC20TransferAmountEnforcer.t.sol @@ -255,8 +255,8 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + + delegation_ = signDelegation(users.alice, delegation_); // Get delegation hash bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); diff --git a/test/enforcers/IdEnforcer.t.sol b/test/enforcers/IdEnforcer.t.sol index 319c45a..b9d4c73 100644 --- a/test/enforcers/IdEnforcer.t.sol +++ b/test/enforcers/IdEnforcer.t.sol @@ -97,8 +97,8 @@ contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + + delegation = signDelegation(users.alice, delegation); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/LimitedCallsEnforcer.t.sol b/test/enforcers/LimitedCallsEnforcer.t.sol index aedae1a..a77a914 100644 --- a/test/enforcers/LimitedCallsEnforcer.t.sol +++ b/test/enforcers/LimitedCallsEnforcer.t.sol @@ -122,8 +122,7 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation_)); + delegation_ = signDelegation(users.alice, delegation_); // Get delegation hash bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); diff --git a/test/enforcers/PasswordEnforcer.t.sol b/test/enforcers/PasswordEnforcer.t.sol index 4beb68c..91569c2 100644 --- a/test/enforcers/PasswordEnforcer.t.sol +++ b/test/enforcers/PasswordEnforcer.t.sol @@ -54,39 +54,7 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { ////////////////////// Integration ////////////////////// - function test_userInputCorrectArgsWorksWithOnchainDelegation() public { - uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - bytes memory inputTerms_ = abi.encode(uint256(12345)); - bytes memory password_ = abi.encode(uint256(12345)); - - Caveat[] memory caveats_ = new Caveat[](1); - caveats_[0] = Caveat({ args: password_, enforcer: address(passwordEnforcer), terms: inputTerms_ }); - Delegation memory delegation = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: caveats_, - salt: 0, - signature: hex"" - }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); - - // Execute Bob's UserOp - Delegation[] memory delegations_ = new Delegation[](1); - delegations_[0] = delegation; - - // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); - // Validate that the count has increased by 1 - assertEq(aliceDeleGatorCounter.count(), initialValue_ + 1); - } - - function test_userInputIncorrectArgsWithOnchainDelegation() public { + function test_userInputIncorrectArgsWithOffchainDelegation() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); // Create the action that would be executed Action memory action_ = @@ -105,8 +73,8 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + + delegation = signDelegation(users.alice, delegation); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/TimestampEnforcer.t.sol b/test/enforcers/TimestampEnforcer.t.sol index af79b3c..a697506 100644 --- a/test/enforcers/TimestampEnforcer.t.sol +++ b/test/enforcers/TimestampEnforcer.t.sol @@ -156,8 +156,8 @@ contract TimestampEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - // Store delegation - execute_UserOp(users.alice, abi.encodeWithSelector(IDelegationManager.delegate.selector, delegation)); + + delegation = signDelegation(users.alice, delegation); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); diff --git a/test/enforcers/ValueLteEnforcer.t.sol b/test/enforcers/ValueLteEnforcer.t.sol index 1e3bc5e..6adf975 100644 --- a/test/enforcers/ValueLteEnforcer.t.sol +++ b/test/enforcers/ValueLteEnforcer.t.sol @@ -51,7 +51,7 @@ contract ValueLteEnforcerTest is CaveatEnforcerBaseTest { } // Validates that valid values don't revert - function test_allow_valueLte() public { + function test_allow_valueLte() public view { // Equal bytes memory terms_ = abi.encodePacked(uint256(1 ether)); Action memory action_ = Action({ diff --git a/test/utils/BaseTest.t.sol b/test/utils/BaseTest.t.sol index 2de7ab1..8489261 100644 --- a/test/utils/BaseTest.t.sol +++ b/test/utils/BaseTest.t.sol @@ -19,7 +19,7 @@ import { TestUser, TestUsers, Implementation, SignatureType } from "./Types.t.so import { SigningUtilsLib } from "./SigningUtilsLib.t.sol"; import { StorageUtilsLib } from "./StorageUtilsLib.t.sol"; import { Action, PackedUserOperation, Delegation } from "../../src/utils/Types.sol"; -import { SimpleFactory } from "./SimpleFactory.sol"; +import { SimpleFactory } from "../../src/utils/SimpleFactory.sol"; import { DelegationManager } from "../../src/DelegationManager.sol"; import { IDeleGatorCoreFull } from "../../src/interfaces/IDeleGatorCoreFull.sol"; import { HybridDeleGator } from "../../src/HybridDeleGator.sol"; From a2784151212074ca09e8c511f224bd5737b76688 Mon Sep 17 00:00:00 2001 From: Hanzel Anchia Mena <33629234+hanzel98@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:36:38 -0600 Subject: [PATCH 5/8] Added Native Allowance Enforcer And Tests (#423) --- script/DeployEnvironmentSetUp.s.sol | 4 + .../NativeTokenTransferAmountEnforcer.sol | 59 ++++++++ test/enforcers/NativeAllowanceEnforcer.t.sol | 130 ++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 src/enforcers/NativeTokenTransferAmountEnforcer.sol create mode 100644 test/enforcers/NativeAllowanceEnforcer.t.sol diff --git a/script/DeployEnvironmentSetUp.s.sol b/script/DeployEnvironmentSetUp.s.sol index 5638150..fff7c86 100644 --- a/script/DeployEnvironmentSetUp.s.sol +++ b/script/DeployEnvironmentSetUp.s.sol @@ -22,6 +22,7 @@ import { LimitedCallsEnforcer } from "../src/enforcers/LimitedCallsEnforcer.sol" import { NonceEnforcer } from "../src/enforcers/NonceEnforcer.sol"; import { TimestampEnforcer } from "../src/enforcers/TimestampEnforcer.sol"; import { ValueLteEnforcer } from "../src/enforcers/ValueLteEnforcer.sol"; +import { NativeTokenTransferAmountEnforcer } from "../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; import { NativeBalanceGteEnforcer } from "../src/enforcers/NativeBalanceGteEnforcer.sol"; /** @@ -102,6 +103,9 @@ contract DeployEnvironmentSetUp is Script { address valueLteEnfocer = address(new ValueLteEnforcer{ salt: salt }()); console2.log("ValueLteEnforcer: %s", address(valueLteEnfocer)); + address nativeTokenTransferAmountEnforcer = address(new NativeTokenTransferAmountEnforcer{ salt: salt }()); + console2.log("NativeTokenTransferAmountEnforcer: %s", address(nativeTokenTransferAmountEnforcer)); + address nativeBalanceGteEnforcer = address(new NativeBalanceGteEnforcer{ salt: salt }()); console2.log("NativeBalanceGteEnforcer: %s", address(nativeBalanceGteEnforcer)); diff --git a/src/enforcers/NativeTokenTransferAmountEnforcer.sol b/src/enforcers/NativeTokenTransferAmountEnforcer.sol new file mode 100644 index 0000000..0665d31 --- /dev/null +++ b/src/enforcers/NativeTokenTransferAmountEnforcer.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { CaveatEnforcer } from "./CaveatEnforcer.sol"; +import { Action } from "../utils/Types.sol"; + +/** + * @title NativeTokenTransferAmountEnforcer + * @notice This contract enforces an allowance of native currency (e.g., ETH) for a specific delegation. + */ +contract NativeTokenTransferAmountEnforcer is CaveatEnforcer { + ////////////////////////////// State ////////////////////////////// + + /// @notice Mapping to store used allowance for each delegation + mapping(address sender => mapping(bytes32 delegationHash => uint256 amount)) public spentMap; + + ////////////////////////////// Events ////////////////////////////// + + event IncreasedSpentMap( + address indexed sender, address indexed redeemer, bytes32 indexed delegationHash, uint256 limit, uint256 spent + ); + + ////////////////////////////// External Functions ////////////////////////////// + + /** + * @notice Enforces the conditions that should hold before a transaction is performed. + * @param _terms The encoded amount of native token allowance. + * @param _action The action of the transaction. + * @param _delegationHash The hash of the delegation. + */ + function beforeHook( + bytes calldata _terms, + bytes calldata, + Action calldata _action, + bytes32 _delegationHash, + address, + address _redeemer + ) + public + override + { + // Decode the total allowance from _terms + uint256 allowance_ = getTermsInfo(_terms); + + uint256 spent_ = spentMap[msg.sender][_delegationHash] += _action.value; + require(spent_ <= allowance_, "NativeTokenTransferAmountEnforcer:allowance-exceeded"); + + emit IncreasedSpentMap(msg.sender, _redeemer, _delegationHash, allowance_, spent_); + } + + /** + * @notice Decodes the terms used in this CaveatEnforcer. + * @param _terms The encoded amount of native token allowance. + * @return allowance_ The maximum number of tokens that the delegate is allowed to transfer. + */ + function getTermsInfo(bytes calldata _terms) public pure returns (uint256 allowance_) { + allowance_ = abi.decode(_terms, (uint256)); + } +} diff --git a/test/enforcers/NativeAllowanceEnforcer.t.sol b/test/enforcers/NativeAllowanceEnforcer.t.sol new file mode 100644 index 0000000..ee5a903 --- /dev/null +++ b/test/enforcers/NativeAllowanceEnforcer.t.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT AND Apache-2.0 +pragma solidity 0.8.23; + +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; +import { NativeTokenTransferAmountEnforcer } from "../../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; +import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; + +contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { + ////////////////////// Set up ////////////////////// + NativeTokenTransferAmountEnforcer public nativeTokenTransferAmountEnforcer; + + function setUp() public override { + super.setUp(); + nativeTokenTransferAmountEnforcer = new NativeTokenTransferAmountEnforcer(); + vm.label(address(nativeTokenTransferAmountEnforcer), "Native Allowance Enforcer"); + } + + //////////////////// Valid cases ////////////////////// + + // Should decode the terms + function test_decodesTheTerms() public { + uint256 obtainedAllowance_ = nativeTokenTransferAmountEnforcer.getTermsInfo(abi.encode(1 ether)); + assertEq(obtainedAllowance_, 1 ether); + } + + // should SUCCEED to INVOKE transfer ETH BELOW enforcer allowance + function test_transferSucceedsIfCalledBelowAllowance() public { + uint256 allowance_ = 1 ether; + + // Create the action that would be executed + Action memory action_ = Action({ to: address(users.bob.deleGator), value: 1 ether, data: hex"" }); + + bytes memory inputTerms_ = abi.encode(allowance_); + + bytes32 delegationHash_ = _getExampleDelegation(inputTerms_); + + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); + vm.prank(address(delegationManager)); + vm.expectEmit(true, true, true, true, address(nativeTokenTransferAmountEnforcer)); + emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( + address(delegationManager), address(0), delegationHash_, allowance_, 1 ether + ); + nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), allowance_); + } + + // should SUCCEED to INVOKE transfer ETH BELOW enforcer allowance + function test_transferSucceedsIfCalledBelowAllowanceMultipleCalls() public { + uint256 allowance_ = 3 ether; + + // Create the action that would be executed + Action memory action_ = Action({ to: address(users.bob.deleGator), value: 1 ether, data: hex"" }); + + bytes memory inputTerms_ = abi.encode(allowance_); + + bytes32 delegationHash_ = _getExampleDelegation(inputTerms_); + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); + vm.startPrank(address(delegationManager)); + + // Fist use + vm.expectEmit(true, true, true, true, address(nativeTokenTransferAmountEnforcer)); + emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( + address(delegationManager), address(0), delegationHash_, allowance_, 1 ether + ); + nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 1 ether); + + // Second use + vm.expectEmit(true, true, true, true, address(nativeTokenTransferAmountEnforcer)); + emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( + address(delegationManager), address(0), delegationHash_, allowance_, 2 ether + ); + nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 2 ether); + + // Third use, maximum allowance used + vm.expectEmit(true, true, true, true, address(nativeTokenTransferAmountEnforcer)); + emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( + address(delegationManager), address(0), delegationHash_, allowance_, allowance_ + ); + nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), allowance_); + } + + ////////////////////// Invalid cases ////////////////////// + + // should FAIL if allowance is exceeded + function test_transferFailsIfAllowanceExceeded() public { + uint256 allowance_ = 1 ether; + + // Create the action that would be executed + // The value is higher than the allowance + Action memory action_ = Action({ to: address(users.bob.deleGator), value: allowance_ + 1, data: hex"" }); + + bytes memory inputTerms_ = abi.encode(allowance_); + + bytes32 delegationHash_ = _getExampleDelegation(inputTerms_); + + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); + vm.prank(address(delegationManager)); + vm.expectRevert("NativeTokenTransferAmountEnforcer:allowance-exceeded"); + nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + + // The allowance does not change + assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); + } + + function _getExampleDelegation(bytes memory inputTerms_) internal view returns (bytes32 delegationHash_) { + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: hex"", enforcer: address(nativeTokenTransferAmountEnforcer), terms: inputTerms_ }); + + Delegation memory delegation_ = Delegation({ + delegate: address(users.bob.deleGator), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: caveats_, + salt: 0, + signature: hex"" + }); + + return EncoderLib._getDelegationHash(delegation_); + } + + function _getEnforcer() internal view override returns (ICaveatEnforcer) { + return ICaveatEnforcer(address(nativeTokenTransferAmountEnforcer)); + } +} From 21ea8d3d4ccc05d4a108c93b203e60bc06251561 Mon Sep 17 00:00:00 2001 From: Hanzel Anchia Mena <33629234+hanzel98@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:45:07 -0600 Subject: [PATCH 6/8] Added Native Token Payment Enforcer (#424) --- script/DeployEnvironmentSetUp.s.sol | 14 + src/enforcers/ArgsEqualityCheckEnforcer.sol | 47 ++ src/enforcers/NativeTokenPaymentEnforcer.sol | 110 ++++ .../enforcers/ArgsEqualityCheckEnforcer.t.sol | 48 ++ .../NativeTokenPaymentEnforcer.t.sol | 473 ++++++++++++++++++ 5 files changed, 692 insertions(+) create mode 100644 src/enforcers/ArgsEqualityCheckEnforcer.sol create mode 100644 src/enforcers/NativeTokenPaymentEnforcer.sol create mode 100644 test/enforcers/ArgsEqualityCheckEnforcer.t.sol create mode 100644 test/enforcers/NativeTokenPaymentEnforcer.t.sol diff --git a/script/DeployEnvironmentSetUp.s.sol b/script/DeployEnvironmentSetUp.s.sol index fff7c86..513e06f 100644 --- a/script/DeployEnvironmentSetUp.s.sol +++ b/script/DeployEnvironmentSetUp.s.sol @@ -12,6 +12,7 @@ import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; import { AllowedCalldataEnforcer } from "../src/enforcers/AllowedCalldataEnforcer.sol"; import { AllowedMethodsEnforcer } from "../src/enforcers/AllowedMethodsEnforcer.sol"; +import { NativeTokenTransferAmountEnforcer } from "../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; import { AllowedTargetsEnforcer } from "../src/enforcers/AllowedTargetsEnforcer.sol"; import { BlockNumberEnforcer } from "../src/enforcers/BlockNumberEnforcer.sol"; import { DeployedEnforcer } from "../src/enforcers/DeployedEnforcer.sol"; @@ -24,6 +25,8 @@ import { TimestampEnforcer } from "../src/enforcers/TimestampEnforcer.sol"; import { ValueLteEnforcer } from "../src/enforcers/ValueLteEnforcer.sol"; import { NativeTokenTransferAmountEnforcer } from "../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; import { NativeBalanceGteEnforcer } from "../src/enforcers/NativeBalanceGteEnforcer.sol"; +import { NativeTokenPaymentEnforcer } from "../src/enforcers/NativeTokenPaymentEnforcer.sol"; +import { ArgsEqualityCheckEnforcer } from "../src/enforcers/ArgsEqualityCheckEnforcer.sol"; /** * @title DeployEnvironmentSetUp @@ -109,6 +112,17 @@ contract DeployEnvironmentSetUp is Script { address nativeBalanceGteEnforcer = address(new NativeBalanceGteEnforcer{ salt: salt }()); console2.log("NativeBalanceGteEnforcer: %s", address(nativeBalanceGteEnforcer)); + address nativeTokenTransferAmountEnforcer = address(new NativeTokenTransferAmountEnforcer{ salt: salt }()); + console2.log("NativeTokenTransferAmountEnforcer: %s", address(nativeTokenTransferAmountEnforcer)); + + address argsEqualityCheckEnforcer = address(new ArgsEqualityCheckEnforcer{ salt: salt }()); + console2.log("ArgsEqualityCheckEnforcer: %s", address(argsEqualityCheckEnforcer)); + + address nativeTokenPaymentEnforcer = address( + new NativeTokenPaymentEnforcer{ salt: salt }(IDelegationManager(delegationManager), address(argsEqualityCheckEnforcer)) + ); + console2.log("NativeTokenPaymentEnforcer: %s", address(nativeTokenPaymentEnforcer)); + vm.stopBroadcast(); } } diff --git a/src/enforcers/ArgsEqualityCheckEnforcer.sol b/src/enforcers/ArgsEqualityCheckEnforcer.sol new file mode 100644 index 0000000..e48cebc --- /dev/null +++ b/src/enforcers/ArgsEqualityCheckEnforcer.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { CaveatEnforcer } from "./CaveatEnforcer.sol"; +import { Action } from "../utils/Types.sol"; + +/** + * * @title ArgsEqualityCheckEnforcer + * @notice Ensures that the provided arguments (`args`) during delegation match the expected terms. + * @dev This caveat enforcer is best used when redeeming delegations where the `delegate` is an immutable contract. + * The contract can populate the `args` for this caveat when redeeming a delegation letting users restrict delegation + * redemption to a when the result of an onchain computation matches the pre-determined `terms` of a delegation. For example, + * if the contract sets the args to the users balance of ETH, the delegation will only be valid when that delegation matches + * the amount set in the `terms`. + */ +contract ArgsEqualityCheckEnforcer is CaveatEnforcer { + ////////////////////////////// Events ////////////////////////////// + + event DifferentArgsAndTerms( + address indexed sender, address indexed redeemer, bytes32 indexed delegationHash, bytes terms, bytes args + ); + ////////////////////////////// External Functions ////////////////////////////// + + /** + * @notice Enforces that the terms and args are the same + * @param _terms Any terms that need to be compared against the args + * @param _args Any args that need to be compared against the terms + * @param _delegationHash The hash of the delegation + * @param _redeemer The address of the redeemer + */ + function beforeHook( + bytes calldata _terms, + bytes calldata _args, + Action calldata, + bytes32 _delegationHash, + address, + address _redeemer + ) + public + override + { + if (keccak256(_terms) != keccak256(_args)) { + emit DifferentArgsAndTerms(msg.sender, _redeemer, _delegationHash, _terms, _args); + revert("ArgsEqualityCheckEnforcer:different-args-and-terms"); + } + } +} diff --git a/src/enforcers/NativeTokenPaymentEnforcer.sol b/src/enforcers/NativeTokenPaymentEnforcer.sol new file mode 100644 index 0000000..40f8e04 --- /dev/null +++ b/src/enforcers/NativeTokenPaymentEnforcer.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { CaveatEnforcer } from "./CaveatEnforcer.sol"; +import { Action, Delegation } from "../utils/Types.sol"; +import { IDelegationManager } from "../interfaces/IDelegationManager.sol"; + +/** + * @title NativeTokenPaymentEnforcer + * @notice This contract enforces payment in native token (e.g., ETH) for the right to use a delegation. + * @dev The redeemer must include a payment delegation in the arguments when executing an action. + * The payment, made in native token, is processed during the execution of the delegated action, ensuring that the + * enforced conditions are met. + * Combining `NativeTokenTransferAmountEnforcer` and `ArgsEqualityCheckEnforcer` when creating the payment delegation is recommended + * to prevent front-running attacks. + */ +contract NativeTokenPaymentEnforcer is CaveatEnforcer { + ////////////////////////////// State ////////////////////////////// + + /// @dev The Delegation Manager contract to redeem the delegation + IDelegationManager public immutable delegationManager; + /// @dev The enforcer used to compare args and terms + address public immutable argsEqualityCheckEnforcer; + + ////////////////////////////// Events ////////////////////////////// + + // Event emitted when a payment is validated + event ValidatedPayment( + address indexed sender, + bytes32 indexed delegationHash, + address indexed recipient, + address delegator, + address redeemer, + uint256 amount + ); + + ////////////////////////////// Constructor ////////////////////////////// + + constructor(IDelegationManager _delegationManager, address _argsEqualityCheckEnforcer) { + delegationManager = _delegationManager; + argsEqualityCheckEnforcer = _argsEqualityCheckEnforcer; + } + + ////////////////////////////// External Functions ////////////////////////////// + + /** + * @notice Enforces the conditions that should hold after a transaction is performed. + * @param _terms Encoded 52 packed bytes where: the first 20 bytes are the address of the recipient, + * the next 32 bytes are the amount to charge for the delegation. + * @param _args Encoded arguments containing the delegation chain for the payment. + * @param _delegationHash The hash of the delegation. + * @param _delegator The address of the delegator. + * @param _redeemer The address that is redeeming the delegation. + */ + function afterHook( + bytes calldata _terms, + bytes calldata _args, + Action calldata, + bytes32 _delegationHash, + address _delegator, + address _redeemer + ) + public + override + { + require(msg.sender == address(delegationManager), "NativeTokenPaymentEnforcer:only-delegation-manager"); + + // Decode the payment terms and arguments + (address recipient_, uint256 amount_) = getTermsInfo(_terms); + + Delegation[] memory delegations_ = abi.decode(_args, (Delegation[])); + + // Assign the delegation hash as the args to the args equality enforcer. + for (uint256 x = 0; x < delegations_.length; ++x) { + Delegation memory delegation_ = delegations_[x]; + for (uint256 i = 0; i < delegation_.caveats.length; ++i) { + if (delegation_.caveats[i].enforcer == argsEqualityCheckEnforcer) { + delegation_.caveats[i].args = abi.encodePacked(_delegationHash); + } + } + } + + bytes memory newEncodedContext_ = abi.encode(delegations_); + + uint256 balanceBefore_ = recipient_.balance; + + // Attempt to redeem the delegation and make the payment + delegationManager.redeemDelegation(newEncodedContext_, Action({ to: recipient_, value: amount_, data: hex"" })); + + // Ensure the recipient received the payment + uint256 balanceAfter_ = recipient_.balance; + require(balanceAfter_ >= balanceBefore_ + amount_, "NativeTokenPaymentEnforcer:payment-not-received"); + + emit ValidatedPayment(msg.sender, _delegationHash, recipient_, _delegator, _redeemer, amount_); + } + + /** + * @notice Decodes the terms used in this CaveatEnforcer. + * @param _terms Encoded 52 packed bytes where: the first 20 bytes are the address of the recipient, + * the next 32 bytes are the amount to charge for the delegation. + * @return recipient_ The recipient that receives the payment. + * @return amount_ The native token amount that must be paid. + */ + function getTermsInfo(bytes calldata _terms) public pure returns (address recipient_, uint256 amount_) { + require(_terms.length == 52, "NativeTokenPaymentEnforcer:invalid-terms-length"); + + recipient_ = address(bytes20(_terms[:20])); + amount_ = uint256(bytes32(_terms[20:])); + } +} diff --git a/test/enforcers/ArgsEqualityCheckEnforcer.t.sol b/test/enforcers/ArgsEqualityCheckEnforcer.t.sol new file mode 100644 index 0000000..2816ce4 --- /dev/null +++ b/test/enforcers/ArgsEqualityCheckEnforcer.t.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT AND Apache-2.0 +pragma solidity 0.8.23; + +import "../../src/utils/Types.sol"; +import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; +import { ArgsEqualityCheckEnforcer } from "../../src/enforcers/ArgsEqualityCheckEnforcer.sol"; +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; + +contract ArgsEqualityCheckEnforcerTest is CaveatEnforcerBaseTest { + ////////////////////// State ////////////////////// + + ArgsEqualityCheckEnforcer public argsEqualityCheckEnforcer; + + ////////////////////// Set up ////////////////////// + + function setUp() public override { + super.setUp(); + argsEqualityCheckEnforcer = new ArgsEqualityCheckEnforcer(); + vm.label(address(argsEqualityCheckEnforcer), "Args Equality Enforcer"); + } + + ////////////////////// Valid cases ////////////////////// + + // should SUCCEED to pass enforcer if terms equals args + function test_passEnforcerWhenTermsEqualsArgs() public { + bytes memory terms_ = bytes("This is an example"); + bytes memory args_ = bytes("This is an example"); + argsEqualityCheckEnforcer.beforeHook(terms_, args_, new Action[](1)[0], bytes32(0), address(0), address(0)); + } + + ////////////////////// Invalid cases ////////////////////// + + // should FAIL to pass enforcer if terms and args are differnt + function test_failToPasEnforcerWhenTermsAndArgsAreDifferent() public { + bytes memory terms_ = bytes("This is an example1"); + bytes memory args_ = bytes("This is an example2"); + address redeemer_ = address(99999); + vm.startPrank(address(delegationManager)); + vm.expectRevert("ArgsEqualityCheckEnforcer:different-args-and-terms"); + vm.expectEmit(true, true, true, true, address(argsEqualityCheckEnforcer)); + emit ArgsEqualityCheckEnforcer.DifferentArgsAndTerms(address(delegationManager), redeemer_, bytes32(0), terms_, args_); + argsEqualityCheckEnforcer.beforeHook(terms_, args_, new Action[](1)[0], bytes32(0), address(0), redeemer_); + } + + function _getEnforcer() internal view override returns (ICaveatEnforcer) { + return ICaveatEnforcer(address(argsEqualityCheckEnforcer)); + } +} diff --git a/test/enforcers/NativeTokenPaymentEnforcer.t.sol b/test/enforcers/NativeTokenPaymentEnforcer.t.sol new file mode 100644 index 0000000..c25457c --- /dev/null +++ b/test/enforcers/NativeTokenPaymentEnforcer.t.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: MIT AND Apache-2.0 +pragma solidity 0.8.23; + +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; +import { NativeTokenPaymentEnforcer } from "../../src/enforcers/NativeTokenPaymentEnforcer.sol"; +import { NativeTokenTransferAmountEnforcer } from "../../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; +import { ArgsEqualityCheckEnforcer } from "../../src/enforcers/ArgsEqualityCheckEnforcer.sol"; +import { LimitedCallsEnforcer } from "../../src/enforcers/LimitedCallsEnforcer.sol"; +import { AllowedTargetsEnforcer } from "../../src/enforcers/AllowedTargetsEnforcer.sol"; +import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; +import { IDelegationManager } from "../../src/interfaces/IDelegationManager.sol"; +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; +import { Counter } from "../utils/Counter.t.sol"; + +contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { + ////////////////////// Set up ////////////////////// + NativeTokenPaymentEnforcer public nativeTokenPaymentEnforcer; + NativeTokenTransferAmountEnforcer public nativeTokenTransferAmountEnforcer; + LimitedCallsEnforcer public limitedCallsEnforcer; + AllowedTargetsEnforcer public allowedTargetsEnforcer; + ArgsEqualityCheckEnforcer public argsEqualityCheckEnforcer; + + function setUp() public override { + super.setUp(); + nativeTokenTransferAmountEnforcer = new NativeTokenTransferAmountEnforcer(); + vm.label(address(nativeTokenTransferAmountEnforcer), "Native Token Transfer Amount Enforcer"); + argsEqualityCheckEnforcer = new ArgsEqualityCheckEnforcer(); + vm.label(address(argsEqualityCheckEnforcer), "Args Equality Check Enforcer"); + nativeTokenPaymentEnforcer = + new NativeTokenPaymentEnforcer(IDelegationManager(address(delegationManager)), address(argsEqualityCheckEnforcer)); + vm.label(address(nativeTokenPaymentEnforcer), "Native Payment Enforcer"); + limitedCallsEnforcer = new LimitedCallsEnforcer(); + vm.label(address(limitedCallsEnforcer), "Limited Calls Enforcer"); + allowedTargetsEnforcer = new AllowedTargetsEnforcer(); + vm.label(address(allowedTargetsEnforcer), "Allowed Targets Enforcer"); + } + + //////////////////// Valid cases ////////////////////// + + // Should decode the terms + function test_decodesTheTerms() public { + address recipient_ = address(users.alice.deleGator); + uint256 amount_ = 1 ether; + bytes memory terms_ = abi.encodePacked(recipient_, amount_); + + (address obtainedRecipient_, uint256 obtainedAmount_) = nativeTokenPaymentEnforcer.getTermsInfo(terms_); + assertEq(obtainedRecipient_, recipient_); + assertEq(obtainedAmount_, amount_); + } + + // Should SUCCEED if the payment is valid + function test_validationPassWithValidPayment() public { + Delegation[] memory paymentDelegations_ = new Delegation[](1); + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](0), + salt: 0, + signature: hex"" + }); + + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + bytes memory args_ = abi.encode(paymentDelegations_); + + address recipient_ = address(users.alice.deleGator); + bytes memory terms_ = abi.encodePacked(recipient_, uint256(1 ether)); + + (bytes32 delegationHash_,) = _getExampleDelegation(terms_, hex""); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + vm.startPrank(address(delegationManager)); + vm.expectEmit(true, true, true, true, address(nativeTokenPaymentEnforcer)); + emit NativeTokenPaymentEnforcer.ValidatedPayment( + address(delegationManager), delegationHash_, recipient_, address(users.alice.deleGator), address(0), 1 ether + ); + + nativeTokenPaymentEnforcer.afterHook(terms_, args_, action_, delegationHash_, address(users.alice.deleGator), address(0)); + } + + // Should SUCCEED to make the payment with a redelegation + function test_validationPassWithValidRedelegationPayment() public { + Delegation[] memory paymentDelegations_ = new Delegation[](2); + paymentDelegations_[1] = Delegation({ + delegate: address(users.bob.deleGator), + delegator: address(users.carol.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](0), + salt: 0, + signature: hex"" + }); + + paymentDelegations_[1] = signDelegation(users.carol, paymentDelegations_[1]); + + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: EncoderLib._getDelegationHash(paymentDelegations_[1]), + caveats: new Caveat[](0), + salt: 0, + signature: hex"" + }); + + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + bytes memory args_ = abi.encode(paymentDelegations_); + + address recipient_ = address(users.alice.deleGator); + bytes memory terms_ = abi.encodePacked(recipient_, uint256(1 ether)); + + (bytes32 delegationHash_,) = _getExampleDelegation(terms_, hex""); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + vm.startPrank(address(delegationManager)); + vm.expectEmit(true, true, true, true, address(nativeTokenPaymentEnforcer)); + emit NativeTokenPaymentEnforcer.ValidatedPayment( + address(delegationManager), delegationHash_, recipient_, address(users.alice.deleGator), address(0), 1 ether + ); + + nativeTokenPaymentEnforcer.afterHook(terms_, args_, action_, delegationHash_, address(users.alice.deleGator), address(0)); + } + + // Should only overwrite the args of the args equality enforcer + function test_onlyOverwriteAllowanceEnforcerArgs() public { + // The terms indicate to send 1 ether to Alice. + address recipient_ = address(users.alice.deleGator); + bytes memory paymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + (bytes32 delegationHash_, Delegation memory paidDelegation_) = _getExampleDelegation(paymentTerms_, hex""); + + Delegation[] memory paidDelegations_ = new Delegation[](1); + paidDelegations_[0] = paidDelegation_; + + // Create the Allowance enforcer + uint256 allowance_ = 1 ether; + bytes memory allowanceTerms_ = abi.encode(allowance_); + bytes memory argsTerms_ = abi.encode(delegationHash_); + + // The args of the nativeTokenTransferAmountEnforcer will ovewriten + // The limitedCallsEnforcer and allowedTargetsEnforcer should stay the same + Caveat[] memory paymentCaveats_ = new Caveat[](4); + paymentCaveats_[0] = Caveat({ args: hex"", enforcer: address(nativeTokenTransferAmountEnforcer), terms: allowanceTerms_ }); + paymentCaveats_[1] = Caveat({ args: hex"", enforcer: address(limitedCallsEnforcer), terms: abi.encodePacked(uint256(10)) }); + paymentCaveats_[2] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(recipient_) }); + paymentCaveats_[3] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsTerms_ }); + + // Create payment delegation from Bob to NativeTokenPaymentEnforcer + Delegation[] memory paymentDelegations_ = new Delegation[](1); + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: ROOT_AUTHORITY, + caveats: paymentCaveats_, + salt: 0, + signature: hex"" + }); + + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + // The args contain the payment delegation to redeem + bytes memory args_ = abi.encode(paymentDelegations_); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + vm.startPrank(address(delegationManager)); + + // Expect this to be overwritten in the event + paymentDelegations_[0].caveats[3].args = abi.encodePacked(delegationHash_); + + // Checks the args of the caveats in the DelegationManager event + vm.expectEmit(true, true, true, true, address(delegationManager)); + emit IDelegationManager.RedeemedDelegation( + paymentDelegations_[0].delegator, address(nativeTokenPaymentEnforcer), paymentDelegations_[0] + ); + nativeTokenPaymentEnforcer.afterHook( + paymentTerms_, args_, action_, delegationHash_, address(users.alice.deleGator), address(0) + ); + } + + ////////////////////// Invalid cases ////////////////////// + + // should FAIL to get terms info when passing an invalid terms length + function test_getTermsInfoFailsForInvalidLength() public { + vm.expectRevert("NativeTokenPaymentEnforcer:invalid-terms-length"); + nativeTokenPaymentEnforcer.getTermsInfo(bytes("1")); + } + + // Should FAIL if the payment is insufficient + function test_validationFailWithInsufficientPayment() public { + address mockDelegationManager_ = address(new MockDelegationManager()); + // Overriding the delegation manager for testing purposes + nativeTokenPaymentEnforcer = + new NativeTokenPaymentEnforcer(IDelegationManager(mockDelegationManager_), address(nativeTokenTransferAmountEnforcer)); + vm.label(address(nativeTokenPaymentEnforcer), "Native Paid Enforcer"); + + Delegation[] memory paymentDelegations_ = new Delegation[](1); + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](0), + salt: 0, + signature: hex"" + }); + + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + // Using a mock delegation manager + bytes memory args_ = abi.encode(paymentDelegations_); + + address recipient_ = address(users.alice.deleGator); + bytes memory terms_ = abi.encodePacked(recipient_, uint256(1 ether)); + + (bytes32 delegationHash_,) = _getExampleDelegation(terms_, hex""); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + vm.startPrank(mockDelegationManager_); + vm.expectRevert("NativeTokenPaymentEnforcer:payment-not-received"); + nativeTokenPaymentEnforcer.afterHook(terms_, args_, action_, delegationHash_, address(0), address(0)); + } + + // Should FAIL if the sender is different from the delegation manager. + function test_validationFailWhenInvalidSender() public { + // Using an invalid sender, it must be the delegation manager + vm.startPrank(address(users.bob.deleGator)); + vm.expectRevert("NativeTokenPaymentEnforcer:only-delegation-manager"); + nativeTokenPaymentEnforcer.afterHook(hex"", hex"", new Action[](1)[0], bytes32(0), address(0), address(0)); + } + + function test_chargePaymentFromAllowance() public { + // The terms indicate to send 1 ether to Alice. + address recipient_ = address(users.alice.deleGator); + bytes memory paymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + (bytes32 delegationHash_, Delegation memory paidDelegation_) = _getExampleDelegation(paymentTerms_, hex""); + + Delegation[] memory paidDelegations_ = new Delegation[](1); + paidDelegations_[0] = paidDelegation_; + + // Create the Allowance enforcer + uint256 allowance_ = 1 ether; + bytes memory allowanceTerms_ = abi.encode(allowance_); + bytes memory argsTerms_ = abi.encode(delegationHash_); + + Caveat[] memory caveats_ = new Caveat[](2); + caveats_[0] = Caveat({ args: hex"", enforcer: address(nativeTokenTransferAmountEnforcer), terms: allowanceTerms_ }); + caveats_[1] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsTerms_ }); + + // Create payment delegation from Bob to NativeTokenPaymentEnforcer + Delegation[] memory paymentDelegations_ = new Delegation[](1); + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: ROOT_AUTHORITY, + caveats: caveats_, + salt: 0, + signature: hex"" + }); + + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + // The args contain the payment delegation to redeem + bytes memory args_ = abi.encode(paymentDelegations_); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + uint256 aliceBalanceBefore_ = address(users.alice.deleGator).balance; + + assertEq(aliceDeleGatorCounter.count(), 0); + + // Pass the delegation payment in the args. + paidDelegations_[0].caveats[0].args = args_; + invokeDelegation_UserOp(users.bob, paidDelegations_, action_); + + assertEq(aliceDeleGatorCounter.count(), 1); + + // Alice received the payment + assertEq(address(users.alice.deleGator).balance, aliceBalanceBefore_ + 1 ether); + } + + function test_delegationFrontRunning() public { + address recipient_ = address(users.alice.deleGator); + bytes memory paymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + // The original terms indicating to send 1 ether to Alice as the payment for Bob + bytes memory originalPaymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + + (, Delegation memory originalPaidDelegation_) = _getExampleDelegation(originalPaymentTerms_, hex""); + Delegation[] memory originalPaidDelegations_ = new Delegation[](1); + originalPaidDelegations_[0] = originalPaidDelegation_; + + // The malicious terms indicating to send 1 ether to Alice as the payment for Carol + bytes memory maliciousPaymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + (, Delegation memory maliciousPaidDelegation_) = _getMaliciousDelegation(maliciousPaymentTerms_, hex""); + Delegation[] memory maliciousPaidDelegations_ = new Delegation[](1); + maliciousPaidDelegations_[0] = maliciousPaidDelegation_; + + // Create the Allowance enforcer (No args enforcer comparison, prone to front-running) + uint256 allowance_ = 1 ether; + bytes memory allowanceTerms_ = abi.encode(allowance_); + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: hex"", enforcer: address(nativeTokenTransferAmountEnforcer), terms: allowanceTerms_ }); + + // Create payment delegation from Bob to NativeTokenPaymentEnforcer + // This delegation is public any one could front-running it + // Even though Bob created this delegation to pay for his Alice delegation, Carol uses this delegation to pay for her. + Delegation[] memory paymentDelegations_ = new Delegation[](1); + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: ROOT_AUTHORITY, + caveats: caveats_, + salt: 0, + signature: hex"" + }); + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + // The args contain the payment delegation to redeem + bytes memory argsWithBobPayment_ = abi.encode(paymentDelegations_); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + uint256 aliceBalanceBefore_ = address(users.alice.deleGator).balance; + + assertEq(aliceDeleGatorCounter.count(), 0); + + // Pass the delegation payment in the args. + maliciousPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; + invokeDelegation_UserOp(users.carol, maliciousPaidDelegations_, action_); + assertEq(aliceDeleGatorCounter.count(), 1); + + // Alice received the payment + assertEq(address(users.alice.deleGator).balance, aliceBalanceBefore_ + 1 ether); + + // Pass the delegation payment in the args. + originalPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; + invokeDelegation_UserOp(users.bob, originalPaidDelegations_, action_); + // The execution did not work because the allowance has already been used. + assertEq(aliceDeleGatorCounter.count(), 1); + } + + function test_delegationArgsEnforcerPreventFrontRunning() public { + // The original terms indicating to send 1 ether to Alice as the payment for Bob + address recipient_ = address(users.alice.deleGator); + bytes memory originalPaymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + + (bytes32 originalPaidDelegationHash_, Delegation memory originalPaidDelegation_) = + _getExampleDelegation(originalPaymentTerms_, hex""); + Delegation[] memory originalPaidDelegations_ = new Delegation[](1); + originalPaidDelegations_[0] = originalPaidDelegation_; + + // The malicious terms indicating to send 1 ether to Alice as the payment for Carol + bytes memory maliciousPaymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + + (, Delegation memory maliciousPaidDelegation_) = _getMaliciousDelegation(maliciousPaymentTerms_, hex""); + Delegation[] memory maliciousPaidDelegations_ = new Delegation[](1); + maliciousPaidDelegations_[0] = maliciousPaidDelegation_; + + // Create the Allowance enforcer (Combined with args enforcer, prevent front-running) + uint256 allowance_ = 1 ether; + bytes memory allowanceTerms_ = abi.encode(allowance_); + bytes memory argsTerms_ = abi.encode(originalPaidDelegationHash_); + + Caveat[] memory caveats_ = new Caveat[](2); + caveats_[0] = Caveat({ args: hex"", enforcer: address(nativeTokenTransferAmountEnforcer), terms: allowanceTerms_ }); + caveats_[1] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsTerms_ }); + + // Create payment delegation from Bob to NativeTokenPaymentEnforcer + // This delegation is public any one could front-running it but it is protected with the args enforcer + // Even though Bob created this delegation to pay for his Alice delegation, Carol tries to use it to pay for her. + Delegation[] memory paymentDelegations_ = new Delegation[](1); + paymentDelegations_[0] = Delegation({ + delegate: address(nativeTokenPaymentEnforcer), + delegator: address(users.bob.deleGator), + authority: ROOT_AUTHORITY, + caveats: caveats_, + salt: 0, + signature: hex"" + }); + paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); + + // The args contain the payment delegation to redeem + bytes memory argsWithBobPayment_ = abi.encode(paymentDelegations_); + + Action memory action_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + uint256 aliceBalanceBefore_ = address(users.alice.deleGator).balance; + + assertEq(aliceDeleGatorCounter.count(), 0); + + // Pass the delegation payment in the args. + maliciousPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; + invokeDelegation_UserOp(users.carol, maliciousPaidDelegations_, action_); + // The execution did not work because the allowance fails due to the invalid args. + assertEq(aliceDeleGatorCounter.count(), 0); + // Alice did not receive the payment + assertEq(address(users.alice.deleGator).balance, aliceBalanceBefore_); + + // Pass the delegation payment in the args. + originalPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; + invokeDelegation_UserOp(users.bob, originalPaidDelegations_, action_); + // The execution works well with a proper args + assertEq(aliceDeleGatorCounter.count(), 1); + // Alice received the payment + assertEq(address(users.alice.deleGator).balance, aliceBalanceBefore_ + 1 ether); + } + + function _getExampleDelegation( + bytes memory inputTerms_, + bytes memory args_ + ) + internal + view + returns (bytes32 delegationHash_, Delegation memory delegation_) + { + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: args_, enforcer: address(nativeTokenPaymentEnforcer), terms: inputTerms_ }); + + delegation_ = Delegation({ + delegate: address(users.bob.deleGator), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: caveats_, + salt: 0, + signature: hex"" + }); + delegation_ = signDelegation(users.alice, delegation_); + delegationHash_ = EncoderLib._getDelegationHash(delegation_); + } + + function _getMaliciousDelegation( + bytes memory inputTerms_, + bytes memory args_ + ) + internal + view + returns (bytes32 delegationHash_, Delegation memory delegation_) + { + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: args_, enforcer: address(nativeTokenPaymentEnforcer), terms: inputTerms_ }); + + delegation_ = Delegation({ + delegate: address(users.carol.deleGator), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: caveats_, + salt: 0, + signature: hex"" + }); + delegation_ = signDelegation(users.alice, delegation_); + delegationHash_ = EncoderLib._getDelegationHash(delegation_); + } + + function _getEnforcer() internal view override returns (ICaveatEnforcer) { + return ICaveatEnforcer(address(nativeTokenPaymentEnforcer)); + } +} + +/// @dev This contract is used for testing a case where the redeemDelegation() function doesn't work as expected +contract MockDelegationManager { + function redeemDelegation(bytes calldata _data, Action calldata _action) external { + // Does not do anything, the action is not processed + } +} From 4ba5e33ae0c152bf433cef5a73fbf869996296f7 Mon Sep 17 00:00:00 2001 From: Aditya Sharma Date: Mon, 19 Aug 2024 02:08:03 +0530 Subject: [PATCH 7/8] Implemented Atomic Batch Redeem Delegation (#426) Co-authored-by: hanzel98 Co-authored-by: Dylan DesRosier --- .gas-snapshot | 348 ------------------ documents/DelegationManager.md | 4 +- script/DeployEnvironmentSetUp.s.sol | 6 +- src/DeleGatorCore.sol | 15 +- src/DelegationManager.sol | 222 ++++++----- src/enforcers/NativeTokenPaymentEnforcer.sol | 10 +- src/interfaces/IDeleGatorCoreFull.sol | 2 +- src/interfaces/IDelegationManager.sol | 8 +- test/CounterfactualAssetsTest.t.sol | 2 +- test/DeleGatorTestSuite.t.sol | 178 +++++---- test/DelegationManagerTest.t.sol | 276 +++++++++++++- test/HybridDeleGatorTest.t.sol | 2 +- test/InviteTest.t.sol | 9 +- test/MultiSigDeleGatorTest.t.sol | 2 +- test/ProxyMigrationTest.t.sol | 2 +- test/enforcers/AllowedCalldataEnforcer.t.sol | 3 +- test/enforcers/AllowedMethodsEnforcer.t.sol | 2 +- test/enforcers/AllowedTargetsEnforcer.t.sol | 2 +- test/enforcers/BlockNumberEnforcer.t.sol | 2 +- .../ERC20TransferAmountEnforcer.t.sol | 2 +- .../NativeTokenPaymentEnforcer.t.sol | 3 +- test/enforcers/TimestampEnforcer.t.sol | 2 +- test/utils/BaseTest.t.sol | 8 +- test/utils/MockCaveatEnforcer.sol | 30 ++ test/utils/MockFailureCaveatEnforcer.sol | 29 ++ 25 files changed, 626 insertions(+), 543 deletions(-) delete mode 100644 .gas-snapshot create mode 100644 test/utils/MockCaveatEnforcer.sol create mode 100644 test/utils/MockFailureCaveatEnforcer.sol diff --git a/.gas-snapshot b/.gas-snapshot deleted file mode 100644 index c661783..0000000 --- a/.gas-snapshot +++ /dev/null @@ -1,348 +0,0 @@ -AllowedCalldataEnforcerTest:test_failsWithInvalidTermsLength() (gas: 19079) -AllowedCalldataEnforcerTest:test_methodCanBeCalledWithSpecificMetadata() (gas: 21884) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualDynamicArrayParam() (gas: 24762) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualDynamicStringParam() (gas: 24132) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualParam() (gas: 18810) -AllowedCalldataEnforcerTest:test_singleMethodCanBeCalledWithEqualParamIntegration() (gas: 411051) -AllowedCalldataEnforcerTest:test_singleMethodCanNotBeCalledWithNonEqualParamIntegration() (gas: 257322) -AllowedCalldataEnforcerTest:test_singleMethodCanNotCalledWithInvalidTermsSize() (gas: 17686) -AllowedCalldataEnforcerTest:test_singleMethodCanNotCalledWithNonEqualParam() (gas: 19293) -AllowedMethodsEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 11216) -AllowedMethodsEnforcerTest:test_methodCanBeSingleMethodIntegration() (gas: 398049) -AllowedMethodsEnforcerTest:test_multiMethodCanBeCalled() (gas: 17942) -AllowedMethodsEnforcerTest:test_notAllow_invalidActionLength() (gas: 15364) -AllowedMethodsEnforcerTest:test_onlyApprovedMethodsCanBeCalled() (gas: 18533) -AllowedMethodsEnforcerTest:test_onlyApprovedMethodsCanBeCalledIntegration() (gas: 256820) -AllowedMethodsEnforcerTest:test_singleMethodCanBeCalled() (gas: 16270) -AllowedTargetsEnforcerTest:testFToken1() (gas: 2395) -AllowedTargetsEnforcerTest:testFToken2() (gas: 2437) -AllowedTargetsEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 11258) -AllowedTargetsEnforcerTest:test_multiTargetCanBeCalled() (gas: 21791) -AllowedTargetsEnforcerTest:test_multiTargetCanBeCalledIntegration() (gas: 659387) -AllowedTargetsEnforcerTest:test_onlyApprovedMethodsCanBeCalledIntegration() (gas: 265602) -AllowedTargetsEnforcerTest:test_onlyApprovedTargetsCanBeCalled() (gas: 24379) -AllowedTargetsEnforcerTest:test_singleTargetCanBeCalled() (gas: 15944) -BlockNumberEnforcerTest:test_getTermsInfoFailsForInvalidLength() (gas: 8962) -BlockNumberEnforcerTest:test_methodCanBeCalledAfterBlockNumber() (gas: 15599) -BlockNumberEnforcerTest:test_methodCanBeCalledAfterBlockNumberIntegration() (gas: 383885) -BlockNumberEnforcerTest:test_methodCanBeCalledBeforeBlockNumber() (gas: 15337) -BlockNumberEnforcerTest:test_methodCanBeCalledInsideBlockNumberRange() (gas: 15734) -BlockNumberEnforcerTest:test_methodFailsIfCalledAfterBlockNumber() (gas: 16185) -BlockNumberEnforcerTest:test_methodFailsIfCalledAfterBlockNumberRange() (gas: 16361) -BlockNumberEnforcerTest:test_methodFailsIfCalledBeforeBlockNumber() (gas: 15769) -BlockNumberEnforcerTest:test_methodFailsIfCalledBeforeBlockNumberRange() (gas: 15849) -CounterfactualAssetsTest:test_allow_createNftAndDelegateWithCaveatsAndRedelegate_offchain() (gas: 2844294) -CounterfactualAssetsTest:test_allow_createNftAndDelegateWithCaveats_offchain() (gas: 2786127) -CounterfactualAssetsTest:test_allow_createNftAndDelegate_offchain() (gas: 2748183) -DelegationManagerTest:test_allow_anyDelegateReads() (gas: 5650) -DelegationManagerTest:test_allow_contractNameReads() (gas: 7230) -DelegationManagerTest:test_allow_contractVersionReads() (gas: 7236) -DelegationManagerTest:test_allow_domainHashReads() (gas: 9454) -DelegationManagerTest:test_allow_domainHashReadsWhenChainIdChanges() (gas: 12627) -DelegationManagerTest:test_allow_domainVersionReads() (gas: 7073) -DelegationManagerTest:test_allow_getDelegationHash() (gas: 15921) -DelegationManagerTest:test_allow_rootAuthorityReads() (gas: 5519) -DelegationManagerTest:test_notAllow_crossDelegationManagerReplays() (gas: 2254890) -DelegationManagerTest:test_notAllow_invalidSignatureReturns() (gas: 129277) -DelegationManagerTest:test_notAllow_invalidSignatureReverts() (gas: 139411) -DelegationManagerTest:test_ownership_transferAndAcceptOwnership() (gas: 36078) -DelegationManagerTest:test_pausability_allowsOwnerToPause() (gas: 39540) -DelegationManagerTest:test_pausability_allowsOwnerToPauseRedemptions() (gas: 37999) -DelegationManagerTest:test_pausability_allowsOwnerToUnpause() (gas: 29340) -DelegationManagerTest:test_pausability_failsToPauseIfNotOwner() (gas: 17635) -DelegationManagerTest:test_pausability_failsToPauseWhenActivePause() (gas: 37313) -DelegationManagerTest:test_pausability_failsToPauseWhenActiveUnpause() (gas: 15075) -DelegationManagerTest:test_pausability_failsToUnpauseIfNotOwner() (gas: 41317) -DelegationManagerTest:test_pausability_validateInitialPauseState() (gas: 1814475) -DeployedEnforcerTest:test_computesAPredictedAddress() (gas: 12693) -DeployedEnforcerTest:test_deploysIfNonExistent() (gas: 165078) -DeployedEnforcerTest:test_deploysIfNonExistentAndAllowsToUseItIntegration() (gas: 435554) -DeployedEnforcerTest:test_doesNotDeployIfExistent() (gas: 118116) -DeployedEnforcerTest:test_revertIfContractIsEmpty() (gas: 55184) -DeployedEnforcerTest:test_revertIfPredictedAddressDoesNotMatch() (gas: 111361) -DeployedEnforcerTest:test_revertIfTermsLengthIsInvalid() (gas: 23352) -DeployedEnforcerTest:test_revertsIfBytecodeDoesntExist() (gas: 111019) -ERC20BalanceGteEnforcerTest:test_allow_ifBalanceIncreases() (gas: 135032) -ERC20BalanceGteEnforcerTest:test_decodedTheTerms() (gas: 9393) -ERC20BalanceGteEnforcerTest:test_invalid_decodedTheTerms() (gas: 15278) -ERC20BalanceGteEnforcerTest:test_invalid_tokenAddress() (gas: 53321) -ERC20BalanceGteEnforcerTest:test_notAllow_expectingOverflow() (gas: 72896) -ERC20BalanceGteEnforcerTest:test_notAllow_insufficientIncrease() (gas: 98127) -ERC20BalanceGteEnforcerTest:test_notAllow_reenterALockedEnforcer() (gas: 154894) -ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidContract() (gas: 31848) -ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidMethod() (gas: 30295) -ERC20TransferAmountEnforcerTest:test_methodFailsIfInvokesInvalidTermsLength() (gas: 29066) -ERC20TransferAmountEnforcerTest:test_notAllow_invalidActionLength() (gas: 29101) -ERC20TransferAmountEnforcerTest:test_transferFailsAboveAllowance() (gas: 548288) -ERC20TransferAmountEnforcerTest:test_transferFailsIfCalledAboveAllowance() (gas: 51151) -ERC20TransferAmountEnforcerTest:test_transferSucceedsIfCalledBelowAllowance() (gas: 56151) -EncoderLibTest:test_ShouldEncodeAnArrayOfCaveats() (gas: 10875) -EncoderLibTest:test_ShouldEncodeOneCaveat() (gas: 5517) -EncoderLibTest:test_shouldEncodeOneDelegation() (gas: 8797) -HybridDeleGator_Test:test_allow_addKey() (gas: 644669) -HybridDeleGator_Test:test_allow_erc173InterfaceId() (gas: 13048) -HybridDeleGator_Test:test_allow_removeKey() (gas: 1032990) -HybridDeleGator_Test:test_allow_replaceEOAWithEOA() (gas: 173966) -HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256() (gas: 276817) -HybridDeleGator_Test:test_allow_replaceEOAWithEOAAndP256WithOffchainDelegation() (gas: 1075663) -HybridDeleGator_Test:test_allow_replaceEOAWithP256() (gas: 268375) -HybridDeleGator_Test:test_allow_signatureWithEOA() (gas: 38383) -HybridDeleGator_Test:test_allow_signatureWithP256() (gas: 410596) -HybridDeleGator_Test:test_allow_signingWithWebAuthn() (gas: 646777) -HybridDeleGator_Test:test_allow_upgradingHybridDeleGator() (gas: 662110) -HybridDeleGator_Test:test_error_replacedSignersInputsMismatch() (gas: 38834) -HybridDeleGator_Test:test_error_replacedSignersToEmpty() (gas: 16079) -HybridDeleGator_Test:test_events_replacedSigners() (gas: 109594) -HybridDeleGator_Test:test_fails_signingWithWebAuthnWithInvalidType() (gas: 219318) -HybridDeleGator_Test:test_initialize_multipleP256OneEOA() (gas: 1032330) -HybridDeleGator_Test:test_initialize_multipleP256ZeroEOA() (gas: 1010140) -HybridDeleGator_Test:test_initialize_zeroP256OneEOA() (gas: 153887) -HybridDeleGator_Test:test_keyAdded_addKey() (gas: 646244) -HybridDeleGator_Test:test_keyAdded_initialize() (gas: 260213) -HybridDeleGator_Test:test_keyRemoved_removeKey() (gas: 1033640) -HybridDeleGator_Test:test_notAllow_addKeyNotOnCurve() (gas: 17527) -HybridDeleGator_Test:test_notAllow_addingAnEmptyKey() (gas: 15327) -HybridDeleGator_Test:test_notAllow_addingExistingKey() (gas: 24863) -HybridDeleGator_Test:test_notAllow_invalidKeyOnDeploy() (gas: 99666) -HybridDeleGator_Test:test_notAllow_invalidSignatureLength() (gas: 22665) -HybridDeleGator_Test:test_notAllow_removingLastKeyViaEOA() (gas: 30437) -HybridDeleGator_Test:test_notAllow_removingLastKeyViaP256() (gas: 27194) -HybridDeleGator_Test:test_notAllow_removingNonExistantKey() (gas: 22288) -HybridDeleGator_Test:test_notAllow_renounceOwnership_Direct() (gas: 19419) -HybridDeleGator_Test:test_notAllow_transferOwnership_directNonOwner() (gas: 16510) -HybridDeleGator_Test:test_notAllow_transferOwnership_directOwner() (gas: 18498) -HybridDeleGator_Test:test_reinitialize_clearsAndSetSigners() (gas: 185988) -HybridDeleGator_Test:test_reinitialize_keepAndSetSigners() (gas: 204732) -HybridDeleGator_Test:test_removeP256KeyAndRearrangeStoredKeyIdHashes() (gas: 173344) -HybridDeleGator_Test:test_return_KeyIdHashes() (gas: 645970) -HybridDeleGator_Test:test_upgradeMultipleTimes() (gas: 523724) -HybridDeleGator_Test:test_upgradeWithoutStorageCleanup() (gas: 438130) -HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 310713) -HybridDeleGator_TestSuite_EOA_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 154109) -HybridDeleGator_TestSuite_EOA_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 261064) -HybridDeleGator_TestSuite_EOA_Test:test_allow_disableOffchainDelegation() (gas: 515436) -HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 106774) -HybridDeleGator_TestSuite_EOA_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 137311) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getDeposit() (gas: 15879) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getEntryPoint() (gas: 12754) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getNonce() (gas: 16208) -HybridDeleGator_TestSuite_EOA_Test:test_allow_getNonceWithKey() (gas: 16334) -HybridDeleGator_TestSuite_EOA_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 300056) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionCombination_UserOp() (gas: 306837) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 308896) -HybridDeleGator_TestSuite_EOA_Test:test_allow_multiAction_UserOp() (gas: 205013) -HybridDeleGator_TestSuite_EOA_Test:test_allow_offchainOpenDelegation() (gas: 323902) -HybridDeleGator_TestSuite_EOA_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 174715) -HybridDeleGator_TestSuite_EOA_Test:test_allow_receiveNativeToken() (gas: 17290) -HybridDeleGator_TestSuite_EOA_Test:test_allow_resetDisabledDelegation() (gas: 273097) -HybridDeleGator_TestSuite_EOA_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 273461) -HybridDeleGator_TestSuite_EOA_Test:test_allow_withdrawDeposit() (gas: 253649) -HybridDeleGator_TestSuite_EOA_Test:test_emit_executedActionEvent() (gas: 69655) -HybridDeleGator_TestSuite_EOA_Test:test_emit_sentPrefund() (gas: 70151) -HybridDeleGator_TestSuite_EOA_Test:test_erc165_supportsInterface() (gas: 19014) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidAuthority() (gas: 275718) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidDelegate() (gas: 218929) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidDelegator() (gas: 187459) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidRootAuthority() (gas: 70344) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidSignature() (gas: 233699) -HybridDeleGator_TestSuite_EOA_Test:test_error_InvalidSigner() (gas: 233478) -HybridDeleGator_TestSuite_EOA_Test:test_error_NoDelegationsProvided() (gas: 209566) -HybridDeleGator_TestSuite_EOA_Test:test_event_Deposited() (gas: 186926) -HybridDeleGator_TestSuite_EOA_Test:test_executesFirstRootAuthorityFound() (gas: 269012) -HybridDeleGator_TestSuite_EOA_Test:test_executionRevertsWithoutReason() (gas: 31686) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 75118) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 76537) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 283684) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 187492) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_delegationWithoutSignature() (gas: 34268) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 302303) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_disablingInvalidDelegation() (gas: 187581) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_emptyAction_UserOp() (gas: 169303) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 199391) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 74187) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidEntryPoint() (gas: 3178940) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidRedeemDelegationData() (gas: 48548) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invalidUserOpSignature() (gas: 132488) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 214398) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_multiActionUserOp() (gas: 192860) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_nonceReuse() (gas: 209787) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_notDelegationManager() (gas: 16708) -HybridDeleGator_TestSuite_EOA_Test:test_notAllow_notEntryPoint() (gas: 16643) -HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 1461507) -HybridDeleGator_TestSuite_P256_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 920655) -HybridDeleGator_TestSuite_P256_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 1019158) -HybridDeleGator_TestSuite_P256_Test:test_allow_disableOffchainDelegation() (gas: 2404096) -HybridDeleGator_TestSuite_P256_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 476935) -HybridDeleGator_TestSuite_P256_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 507472) -HybridDeleGator_TestSuite_P256_Test:test_allow_getDeposit() (gas: 15879) -HybridDeleGator_TestSuite_P256_Test:test_allow_getEntryPoint() (gas: 12754) -HybridDeleGator_TestSuite_P256_Test:test_allow_getNonce() (gas: 16208) -HybridDeleGator_TestSuite_P256_Test:test_allow_getNonceWithKey() (gas: 16334) -HybridDeleGator_TestSuite_P256_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 1065126) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionCombination_UserOp() (gas: 1078370) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 1457506) -HybridDeleGator_TestSuite_P256_Test:test_allow_multiAction_UserOp() (gas: 573813) -HybridDeleGator_TestSuite_P256_Test:test_allow_offchainOpenDelegation() (gas: 1450370) -HybridDeleGator_TestSuite_P256_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 930472) -HybridDeleGator_TestSuite_P256_Test:test_allow_receiveNativeToken() (gas: 17290) -HybridDeleGator_TestSuite_P256_Test:test_allow_resetDisabledDelegation() (gas: 1037480) -HybridDeleGator_TestSuite_P256_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 1035884) -HybridDeleGator_TestSuite_P256_Test:test_allow_withdrawDeposit() (gas: 1012917) -HybridDeleGator_TestSuite_P256_Test:test_emit_executedActionEvent() (gas: 69655) -HybridDeleGator_TestSuite_P256_Test:test_emit_sentPrefund() (gas: 70151) -HybridDeleGator_TestSuite_P256_Test:test_erc165_supportsInterface() (gas: 19014) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidAuthority() (gas: 1430056) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidDelegate() (gas: 612259) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidDelegator() (gas: 575654) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidRootAuthority() (gas: 466977) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidSignature() (gas: 624753) -HybridDeleGator_TestSuite_P256_Test:test_error_InvalidSigner() (gas: 624532) -HybridDeleGator_TestSuite_P256_Test:test_error_NoDelegationsProvided() (gas: 594641) -HybridDeleGator_TestSuite_P256_Test:test_event_Deposited() (gas: 566929) -HybridDeleGator_TestSuite_P256_Test:test_executesFirstRootAuthorityFound() (gas: 1427080) -HybridDeleGator_TestSuite_P256_Test:test_executionRevertsWithoutReason() (gas: 31686) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 76900) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 78320) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 1444840) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 571310) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_delegationWithoutSignature() (gas: 34268) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 1076766) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_disablingInvalidDelegation() (gas: 576711) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_emptyAction_UserOp() (gas: 558220) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 591984) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 76049) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidEntryPoint() (gas: 3182587) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidRedeemDelegationData() (gas: 50410) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invalidUserOpSignature() (gas: 132806) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 607728) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_multiActionUserOp() (gas: 576810) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_nonceReuse() (gas: 966786) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_notDelegationManager() (gas: 16708) -HybridDeleGator_TestSuite_P256_Test:test_notAllow_notEntryPoint() (gas: 16643) -IdEnforcerEnforcerTest:testFToken1() (gas: 2439) -IdEnforcerEnforcerTest:test_blocksDelegationWithRepeatedNonce() (gas: 49111) -IdEnforcerEnforcerTest:test_decodedTheTerms() (gas: 6304) -IdEnforcerEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 13237) -IdEnforcerEnforcerTest:test_methodFailsIfNonceAlreadyUsed() (gas: 407040) -InviteTest:test_createADeleGatorForBobAndDelegate() (gas: 555272) -InviteTest:test_createADeleGatorForBobAndSend() (gas: 426810) -LimitedCallsEnforcerTest:test_methodCanBeCalledBelowLimitNumber() (gas: 53639) -LimitedCallsEnforcerTest:test_methodFailsAboveLimitIntegration() (gas: 410960) -LimitedCallsEnforcerTest:test_methodFailsIfCalledAboveLimitNumber() (gas: 53929) -LimitedCallsEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 13393) -MultiSigDeleGatorTest:test_DelegationManagerSetEvent() (gas: 2802132) -MultiSigDeleGatorTest:test_ImplementationUsesMaxThreshold() (gas: 7584) -MultiSigDeleGatorTest:test_InitializedImplementationEvent() (gas: 2802004) -MultiSigDeleGatorTest:test_InitializedSignersEvents() (gas: 334328) -MultiSigDeleGatorTest:test_ReinitializedSignersEvents() (gas: 140910) -MultiSigDeleGatorTest:test_allow_addSigner() (gas: 81864) -MultiSigDeleGatorTest:test_allow_deploySCAWithInitCode() (gas: 411169) -MultiSigDeleGatorTest:test_allow_getMaxSigners() (gas: 10474) -MultiSigDeleGatorTest:test_allow_getSignersCount() (gas: 12657) -MultiSigDeleGatorTest:test_allow_invokeOffchainDelegationWithMultipleSigners() (gas: 287181) -MultiSigDeleGatorTest:test_allow_removeSigner() (gas: 220380) -MultiSigDeleGatorTest:test_allow_replaceSigner() (gas: 222189) -MultiSigDeleGatorTest:test_allow_updateMultiSigParameters_base() (gas: 547816) -MultiSigDeleGatorTest:test_allow_updatingThreshold() (gas: 81137) -MultiSigDeleGatorTest:test_error_Init_AlreadyASigner() (gas: 164347) -MultiSigDeleGatorTest:test_error_Init_InvalidSignerAddress() (gas: 95386) -MultiSigDeleGatorTest:test_error_Init_InvalidSignersLength() (gas: 264732) -MultiSigDeleGatorTest:test_error_Init_InvalidThreshold() (gas: 182347) -MultiSigDeleGatorTest:test_error_Init_thresholdGreaterThanSigners() (gas: 119497) -MultiSigDeleGatorTest:test_error_updateSigParamatersAlreadyASigner() (gas: 71786) -MultiSigDeleGatorTest:test_error_updateSigParamatersContractNewSigner() (gas: 24948) -MultiSigDeleGatorTest:test_error_updateSigParamatersZeroNewSigner() (gas: 20222) -MultiSigDeleGatorTest:test_error_updateSigParametersInvalidThreshold() (gas: 17404) -MultiSigDeleGatorTest:test_notAllow_addSigner() (gas: 1579287) -MultiSigDeleGatorTest:test_notAllow_invalidSignatureLength() (gas: 163315) -MultiSigDeleGatorTest:test_notAllow_invalidSigners() (gas: 177010) -MultiSigDeleGatorTest:test_notAllow_removeSigner() (gas: 110994) -MultiSigDeleGatorTest:test_notAllow_replaceSigner() (gas: 53557) -MultiSigDeleGatorTest:test_notAllow_signerReuse() (gas: 166498) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_access() (gas: 37408) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_maxNumberOfSigners() (gas: 31099) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_threshold() (gas: 32235) -MultiSigDeleGatorTest:test_notAllow_updateMultiSigParameters_thresholdKeepingSigners() (gas: 26762) -MultiSigDeleGatorTest:test_notAllow_updatingThreshold() (gas: 86116) -MultiSigDeleGatorTest:test_reinitialize_clearsAndSetSigners() (gas: 128542) -MultiSigDeleGatorTest:test_reinitialize_keepAndSetSigners() (gas: 146141) -MultiSigDeleGatorTest:test_return_ifAnAddressIsAValidSigner() (gas: 20724) -MultiSigDeleGatorTest:test_unauthorizedReinitializeCall() (gas: 24240) -MultiSig_TestSuite_Test:test_allow_chainOfOffchainDelegationToDeleGators() (gas: 324649) -MultiSig_TestSuite_Test:test_allow_chainOfOffchainDelegationToEoa() (gas: 163346) -MultiSig_TestSuite_Test:test_allow_deleGatorInvokeOffchainDelegation() (gas: 270369) -MultiSig_TestSuite_Test:test_allow_disableOffchainDelegation() (gas: 531088) -MultiSig_TestSuite_Test:test_allow_eoaInvokeOffchainDelegation() (gas: 111381) -MultiSig_TestSuite_Test:test_allow_eoaRedelegateOffchainDelegation() (gas: 141919) -MultiSig_TestSuite_Test:test_allow_getDeposit() (gas: 15879) -MultiSig_TestSuite_Test:test_allow_getEntryPoint() (gas: 12754) -MultiSig_TestSuite_Test:test_allow_getNonce() (gas: 16186) -MultiSig_TestSuite_Test:test_allow_getNonceWithKey() (gas: 16400) -MultiSig_TestSuite_Test:test_allow_invokeOffchainDelegationWithCaveats() (gas: 309361) -MultiSig_TestSuite_Test:test_allow_multiActionCombination_UserOp() (gas: 316099) -MultiSig_TestSuite_Test:test_allow_multiActionDelegationClaim_Offchain_UserOp() (gas: 319260) -MultiSig_TestSuite_Test:test_allow_multiAction_UserOp() (gas: 209598) -MultiSig_TestSuite_Test:test_allow_offchainOpenDelegation() (gas: 334242) -MultiSig_TestSuite_Test:test_allow_offchainOpenDelegationRedelegation() (gas: 183952) -MultiSig_TestSuite_Test:test_allow_receiveNativeToken() (gas: 17290) -MultiSig_TestSuite_Test:test_allow_resetDisabledDelegation() (gas: 280225) -MultiSig_TestSuite_Test:test_allow_updatingOffchainDelegationDisabledStateWithStruct() (gas: 280633) -MultiSig_TestSuite_Test:test_allow_withdrawDeposit() (gas: 260866) -MultiSig_TestSuite_Test:test_emit_executedActionEvent() (gas: 69611) -MultiSig_TestSuite_Test:test_emit_sentPrefund() (gas: 72559) -MultiSig_TestSuite_Test:test_erc165_supportsInterface() (gas: 18729) -MultiSig_TestSuite_Test:test_error_InvalidAuthority() (gas: 289678) -MultiSig_TestSuite_Test:test_error_InvalidDelegate() (gas: 225199) -MultiSig_TestSuite_Test:test_error_InvalidDelegator() (gas: 192155) -MultiSig_TestSuite_Test:test_error_InvalidRootAuthority() (gas: 74973) -MultiSig_TestSuite_Test:test_error_InvalidSignature() (gas: 242928) -MultiSig_TestSuite_Test:test_error_InvalidSigner() (gas: 242707) -MultiSig_TestSuite_Test:test_error_NoDelegationsProvided() (gas: 215836) -MultiSig_TestSuite_Test:test_event_Deposited() (gas: 191511) -MultiSig_TestSuite_Test:test_executesFirstRootAuthorityFound() (gas: 282970) -MultiSig_TestSuite_Test:test_executionRevertsWithoutReason() (gas: 31664) -MultiSig_TestSuite_Test:test_notAllow_callFromNonProxyAddress_IsValidSignature() (gas: 76690) -MultiSig_TestSuite_Test:test_notAllow_callFromNonProxyAddress_ValidateUserOp() (gas: 78110) -MultiSig_TestSuite_Test:test_notAllow_chainOfOffchainDelegationToDeleGators() (gas: 297643) -MultiSig_TestSuite_Test:test_notAllow_delegatingForAnotherDelegator() (gas: 192188) -MultiSig_TestSuite_Test:test_notAllow_delegationWithoutSignature() (gas: 34335) -MultiSig_TestSuite_Test:test_notAllow_disableAlreadyDisabledDelegation() (gas: 310983) -MultiSig_TestSuite_Test:test_notAllow_disablingInvalidDelegation() (gas: 192189) -MultiSig_TestSuite_Test:test_notAllow_emptyAction_UserOp() (gas: 173888) -MultiSig_TestSuite_Test:test_notAllow_enableAlreadyEnabledDelegation() (gas: 205659) -MultiSig_TestSuite_Test:test_notAllow_eoaRedelegateOffchainDelegation() (gas: 75759) -MultiSig_TestSuite_Test:test_notAllow_invalidEntryPoint() (gas: 3182070) -MultiSig_TestSuite_Test:test_notAllow_invalidRedeemDelegationData() (gas: 50119) -MultiSig_TestSuite_Test:test_notAllow_invalidUserOpSignature() (gas: 137019) -MultiSig_TestSuite_Test:test_notAllow_invokeOffchainDelegationToAnotherUser() (gas: 220668) -MultiSig_TestSuite_Test:test_notAllow_multiActionUserOp() (gas: 197445) -MultiSig_TestSuite_Test:test_notAllow_nonceReuse() (gas: 215451) -MultiSig_TestSuite_Test:test_notAllow_notDelegationManager() (gas: 16686) -MultiSig_TestSuite_Test:test_notAllow_notEntryPoint() (gas: 16621) -NonceEnforcerTest:test_allow_incrementingId() (gas: 42105) -NonceEnforcerTest:test_allow_validId() (gas: 24403) -NonceEnforcerTest:test_decodedTheTerms() (gas: 9365) -NonceEnforcerTest:test_invalid_decodedTheTerms() (gas: 12704) -NonceEnforcerTest:test_notAllow_invalidId() (gas: 54844) -PasswordEnforcerTest:test_userInputCorrectArgsWorks() (gas: 14996) -PasswordEnforcerTest:test_userInputCorrectArgsWorksWithOffchainDelegation() (gas: 279347) -PasswordEnforcerTest:test_userInputIncorrectArgs() (gas: 15445) -PasswordEnforcerTest:test_userInputIncorrectArgsWithOffchainDelegation() (gas: 253774) -PasswordEnforcerTest:test_userInputIncorrectArgsWorksWithOffchainDelegation() (gas: 243638) -StorageUtilsLibTest:testToBool() (gas: 11185) -TimestampEnforcerTest:test_methodCanBeCalledAfterTimestamp() (gas: 15761) -TimestampEnforcerTest:test_methodCanBeCalledAfterTimestampIntegration() (gas: 384168) -TimestampEnforcerTest:test_methodCanBeCalledBeforeTimestamp() (gas: 15336) -TimestampEnforcerTest:test_methodCanBeCalledInsideTimestampRange() (gas: 15873) -TimestampEnforcerTest:test_methodFailsIfCalledAfterTimestamp() (gas: 16254) -TimestampEnforcerTest:test_methodFailsIfCalledAfterTimestampRange() (gas: 16473) -TimestampEnforcerTest:test_methodFailsIfCalledBeforeTimestampRange() (gas: 15848) -TimestampEnforcerTest:test_methodFailsIfCalledTimestamp() (gas: 15770) -TimestampEnforcerTest:test_methodFailsIfCalledWithInvalidInputTerms() (gas: 13421) -TypehashTest:test_CaveatTypehash() (gas: 7615) -TypehashTest:test_DelegationTypehash() (gas: 18191) -TypehashTest:test_EIP712DomainTypehash() (gas: 9844) -ValueLteEnforcerTest:test_allow_decodeTerms() (gas: 9277) -ValueLteEnforcerTest:test_allow_valueLte() (gas: 12381) -ValueLteEnforcerTest:test_notAllow_decodeTerms() (gas: 14911) -ValueLteEnforcerTest:test_notAllow_valueGt() (gas: 12958) \ No newline at end of file diff --git a/documents/DelegationManager.md b/documents/DelegationManager.md index bcf280e..8b9b1b2 100644 --- a/documents/DelegationManager.md +++ b/documents/DelegationManager.md @@ -4,7 +4,7 @@ A Delegation Manager is responsible for validating delegations and triggering th ## Rules -- A Delegation Manager MUST implement `redeemDelegation` interface as specified `function redeemDelegation(bytes calldata _data, Action calldata _action) external;`. +- A Delegation Manager MUST implement `redeemDelegation` interface as specified `function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external;`. ## Delegations @@ -34,7 +34,7 @@ Open delegations are delegations that don't have a strict `delegate`. By setting Our `DelegationManager` implementation: -1. `redeemDelegation` consumes a list of delegations (`Delegation[]`) and an `Action` to be executed +1. `redeemDelegation` consumes an array of bytes with the encoded delegation chains (`Delegation[]`) for executing each of the `Action`. > NOTE: Delegations are ordered from leaf to root. The last delegation in the array must have the root authority. 2. Validates the `msg.sender` calling `redeemDelegation` is allowed to do so 3. Validates the signatures of offchain delegations. diff --git a/script/DeployEnvironmentSetUp.s.sol b/script/DeployEnvironmentSetUp.s.sol index 513e06f..4f53c15 100644 --- a/script/DeployEnvironmentSetUp.s.sol +++ b/script/DeployEnvironmentSetUp.s.sol @@ -23,7 +23,6 @@ import { LimitedCallsEnforcer } from "../src/enforcers/LimitedCallsEnforcer.sol" import { NonceEnforcer } from "../src/enforcers/NonceEnforcer.sol"; import { TimestampEnforcer } from "../src/enforcers/TimestampEnforcer.sol"; import { ValueLteEnforcer } from "../src/enforcers/ValueLteEnforcer.sol"; -import { NativeTokenTransferAmountEnforcer } from "../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; import { NativeBalanceGteEnforcer } from "../src/enforcers/NativeBalanceGteEnforcer.sol"; import { NativeTokenPaymentEnforcer } from "../src/enforcers/NativeTokenPaymentEnforcer.sol"; import { ArgsEqualityCheckEnforcer } from "../src/enforcers/ArgsEqualityCheckEnforcer.sol"; @@ -108,13 +107,10 @@ contract DeployEnvironmentSetUp is Script { address nativeTokenTransferAmountEnforcer = address(new NativeTokenTransferAmountEnforcer{ salt: salt }()); console2.log("NativeTokenTransferAmountEnforcer: %s", address(nativeTokenTransferAmountEnforcer)); - + address nativeBalanceGteEnforcer = address(new NativeBalanceGteEnforcer{ salt: salt }()); console2.log("NativeBalanceGteEnforcer: %s", address(nativeBalanceGteEnforcer)); - address nativeTokenTransferAmountEnforcer = address(new NativeTokenTransferAmountEnforcer{ salt: salt }()); - console2.log("NativeTokenTransferAmountEnforcer: %s", address(nativeTokenTransferAmountEnforcer)); - address argsEqualityCheckEnforcer = address(new ArgsEqualityCheckEnforcer{ salt: salt }()); console2.log("ArgsEqualityCheckEnforcer: %s", address(argsEqualityCheckEnforcer)); diff --git a/src/DeleGatorCore.sol b/src/DeleGatorCore.sol index f87b384..71da3f6 100644 --- a/src/DeleGatorCore.sol +++ b/src/DeleGatorCore.sol @@ -112,15 +112,14 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel receive() external payable { } /** - * @notice Redeems a delegation on the DelegationManager and executes the action as the root delegator - * @dev `_data` is made up of an array of `Delegation` structs that are used to validate the authority given to execute the - * action - * on the root delegator ordered from leaf to root. - * @param _data the data used to validate the authority given to execute the action - * @param _action The action to be executed + * @notice Redeems a delegation on the DelegationManager and executes the specified actions on behalf of the root delegator. + * @param _permissionContexts An array of bytes where each element is made up of an array + * of `Delegation` structs that are used to validate the authority given to execute the corresponding action on the + * root delegator, ordered from leaf to root. + * @param _actions An array of `Action` structs representing the actions to be executed. */ - function redeemDelegation(bytes calldata _data, Action calldata _action) external onlyEntryPointOrSelf { - delegationManager.redeemDelegation(_data, _action); + function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external onlyEntryPointOrSelf { + delegationManager.redeemDelegation(_permissionContexts, _actions); } /// @inheritdoc IDeleGatorCore diff --git a/src/DelegationManager.sol b/src/DelegationManager.sol index 7aca4ae..c82f770 100644 --- a/src/DelegationManager.sol +++ b/src/DelegationManager.sol @@ -108,112 +108,162 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 } /** - * @notice This method validates the provided data and executes the action if the caller has authority to do so. - * @dev _data is made up of an array of `Delegation` structs that are used to validate the authority given to execute the action - * on the root delegator ordered from leaf to root. - * @dev Delegations can be invalidated for a number of reasons at any moment including invalid signatures due to ownership - * changes, disabled delegations or arbitrary caveat - * restrictions. Be sure to validate offchain before submitting anything onchain. - * @dev Delegations are ordered from leaf to root. The last delegation in the array must have the root authority. - * @dev Delegations are signed by the delegator and are validated at the time of redemption. - * @dev Caveats are enforced with the order: `beforeHook` from leaf to root, execute action, `afterHook` from root to leaf - * @param _data the data used to validate the authority given to execute the action. - * @param _action the action to be executed + * @notice This method validates the provided permission contexts and executes the action if the caller has authority to do so. + * @dev The structure of the _permissionContexts array is determined by the specific Delegation Manager implementation + * If an entry in _permissionsContexts is empty (i.e., its length is 0), it is treated as a self-authorized action. + * @dev The length of _permissionsContexts must match the length of _actions. + * @dev The afterHook calls of all the caveat enforcers are called after the execution of all the actions in the batch. + * @dev If any afterHook fails, the entire transaction will revert. + * @param _permissionContexts An array of bytes where each element is made up of an array + * of `Delegation` structs that are used to validate the authority given to execute the corresponding action on the + * root delegator, ordered from leaf to root. + * @param _actions the array of actions to be executed */ - function redeemDelegation(bytes calldata _data, Action calldata _action) external whenNotPaused { - Delegation[] memory delegations_ = abi.decode(_data, (Delegation[])); + function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external whenNotPaused { + uint256 batchSize_ = _permissionContexts.length; + if (batchSize_ != _actions.length) revert BatchDataLengthMismatch(); - // Validate caller - if (delegations_.length == 0) { - revert NoDelegationsProvided(); - } - - // Load delegation hashes and validate signatures (leaf to root) - bytes32[] memory delegationHashes_ = new bytes32[](delegations_.length); - Delegation memory delegation_; + Delegation[][] memory batchDelegations_ = new Delegation[][](batchSize_); + bytes32[][] memory batchDelegationHashes_ = new bytes32[][](batchSize_); - // Validate caller - if (delegations_[0].delegate != msg.sender && delegations_[0].delegate != ANY_DELEGATE) { - revert InvalidDelegate(); - } + // Validate and process delegations for each action + for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { + Delegation[] memory delegations_ = abi.decode(_permissionContexts[batchIndex_], (Delegation[])); - for (uint256 i; i < delegations_.length; ++i) { - delegation_ = delegations_[i]; - delegationHashes_[i] = EncoderLib._getDelegationHash(delegation_); - - if (delegation_.signature.length == 0) { - // Ensure that delegations without signatures revert - revert EmptySignature(); - } - // Check if the delegator is an EOA or a contract - address delegator_ = delegation_.delegator; - - if (delegator_.code.length == 0) { - // Validate delegation if it's an EOA - address result_ = - ECDSA.recover(MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[i]), delegation_.signature); - if (result_ != delegator_) revert InvalidSignature(); + if (delegations_.length == 0) { + // Special case: If the permissionContext is empty, treat it as a self authorized action + batchDelegations_[batchIndex_] = new Delegation[](0); + batchDelegationHashes_[batchIndex_] = new bytes32[](0); } else { - // Validate delegation if it's a contract - bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[i]); + batchDelegations_[batchIndex_] = delegations_; + + // Load delegation hashes and validate signatures (leaf to root) + bytes32[] memory delegationHashes_ = new bytes32[](delegations_.length); + batchDelegationHashes_[batchIndex_] = delegationHashes_; + + // Validate caller + if (delegations_[0].delegate != msg.sender && delegations_[0].delegate != ANY_DELEGATE) revert InvalidDelegate(); + + for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { + Delegation memory delegation_ = delegations_[delegationsIndex_]; + delegationHashes_[delegationsIndex_] = EncoderLib._getDelegationHash(delegation_); + + if (delegation_.signature.length == 0) { + // Ensure that delegations without signatures revert + revert EmptySignature(); + } + + // Check if the delegator is an EOA or a contract + address delegator_ = delegation_.delegator; + + if (delegator_.code.length == 0) { + // Validate delegation if it's an EOA + address result_ = ECDSA.recover( + MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[delegationsIndex_]), + delegation_.signature + ); + if (result_ != delegator_) revert InvalidSignature(); + } else { + // Validate delegation if it's a contract + bytes32 typedDataHash_ = + MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[delegationsIndex_]); + + bytes32 result_ = IERC1271(delegator_).isValidSignature(typedDataHash_, delegation_.signature); + if (result_ != ERC1271Lib.EIP1271_MAGIC_VALUE) { + revert InvalidSignature(); + } + } + } - bytes32 result_ = IERC1271(delegator_).isValidSignature(typedDataHash_, delegation_.signature); - if (result_ != ERC1271Lib.EIP1271_MAGIC_VALUE) { - revert InvalidSignature(); + // Validate authority and delegate (leaf to root) + for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { + // Validate if delegation is disabled + if (disabledDelegations[delegationHashes_[delegationsIndex_]]) { + revert CannotUseADisabledDelegation(); + } + + // Validate authority + if (delegationsIndex_ != delegations_.length - 1) { + if (delegations_[delegationsIndex_].authority != delegationHashes_[delegationsIndex_ + 1]) { + revert InvalidAuthority(); + } + // Validate delegate + address nextDelegate_ = delegations_[delegationsIndex_ + 1].delegate; + if (nextDelegate_ != ANY_DELEGATE && delegations_[delegationsIndex_].delegator != nextDelegate_) { + revert InvalidDelegate(); + } + } else if (delegations_[delegationsIndex_].authority != ROOT_AUTHORITY) { + revert InvalidAuthority(); + } } } } - // (leaf to root) - for (uint256 i; i < delegations_.length; ++i) { - // Validate if delegation is disabled - if (disabledDelegations[delegationHashes_[i]]) { - revert CannotUseADisabledDelegation(); - } - - // Validate authority - if (i != delegations_.length - 1) { - if (delegations_[i].authority != delegationHashes_[i + 1]) { - revert InvalidAuthority(); - } - // Validate delegate - address nextDelegate = delegations_[i + 1].delegate; - if (nextDelegate != ANY_DELEGATE && delegations_[i].delegator != nextDelegate) { - revert InvalidDelegate(); + // beforeHook (leaf to root) + for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { + if (batchDelegations_[batchIndex_].length > 0) { + Delegation[] memory delegations_ = batchDelegations_[batchIndex_]; + bytes32[] memory delegationHashes_ = batchDelegationHashes_[batchIndex_]; + // Execute beforeHooks + for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { + Caveat[] memory caveats_ = delegations_[delegationsIndex_].caveats; + for (uint256 caveatsIndex_; caveatsIndex_ < caveats_.length; ++caveatsIndex_) { + ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[caveatsIndex_].enforcer); + enforcer_.beforeHook( + caveats_[caveatsIndex_].terms, + caveats_[caveatsIndex_].args, + _actions[batchIndex_], + delegationHashes_[delegationsIndex_], + delegations_[delegationsIndex_].delegator, + msg.sender + ); + } } - } else if (delegations_[i].authority != ROOT_AUTHORITY) { - revert InvalidAuthority(); } } - // beforeHook (leaf to root) - for (uint256 i; i < delegations_.length; ++i) { - Caveat[] memory caveats_ = delegations_[i].caveats; - bytes32 delegationHash_ = delegationHashes_[i]; - address delegator_ = delegations_[i].delegator; - uint256 caveatsLength_ = caveats_.length; - for (uint256 j; j < caveatsLength_; ++j) { - ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[j].enforcer); - enforcer_.beforeHook(caveats_[j].terms, caveats_[j].args, _action, delegationHash_, delegator_, msg.sender); + for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { + if (batchDelegations_[batchIndex_].length == 0) { + // special case: If there are no delegations, defer the call to the caller. + IDeleGatorCore(msg.sender).executeDelegatedAction(_actions[batchIndex_]); + } else { + IDeleGatorCore(batchDelegations_[batchIndex_][batchDelegations_[batchIndex_].length - 1].delegator) + .executeDelegatedAction(_actions[batchIndex_]); } } - // Execute action (root) - IDeleGatorCore(delegations_[delegations_.length - 1].delegator).executeDelegatedAction(_action); - // afterHook (root to leaf) - for (uint256 i = delegations_.length; i > 0; --i) { - Caveat[] memory caveats_ = delegations_[i - 1].caveats; - bytes32 delegationHash_ = delegationHashes_[i - 1]; - address delegator_ = delegations_[i - 1].delegator; - uint256 caveatsLength_ = caveats_.length; - for (uint256 j; j < caveatsLength_; ++j) { - ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[j].enforcer); - enforcer_.afterHook(caveats_[j].terms, caveats_[j].args, _action, delegationHash_, delegator_, msg.sender); + for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { + if (batchDelegations_[batchIndex_].length > 0) { + Delegation[] memory delegations_ = batchDelegations_[batchIndex_]; + bytes32[] memory delegationHashes_ = batchDelegationHashes_[batchIndex_]; + // Execute afterHooks + for (uint256 delegationsIndex_ = delegations_.length; delegationsIndex_ > 0; --delegationsIndex_) { + Caveat[] memory caveats_ = delegations_[delegationsIndex_ - 1].caveats; + for (uint256 caveatsIndex_; caveatsIndex_ < caveats_.length; ++caveatsIndex_) { + ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[caveatsIndex_].enforcer); + enforcer_.afterHook( + caveats_[caveatsIndex_].terms, + caveats_[caveatsIndex_].args, + _actions[batchIndex_], + delegationHashes_[delegationsIndex_ - 1], + delegations_[delegationsIndex_ - 1].delegator, + msg.sender + ); + } + } } } - for (uint256 i; i < delegations_.length; ++i) { - emit RedeemedDelegation(delegations_[delegations_.length - 1].delegator, msg.sender, delegations_[i]); + + for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { + if (batchDelegations_[batchIndex_].length > 0) { + Delegation[] memory delegations_ = batchDelegations_[batchIndex_]; + for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { + emit RedeemedDelegation( + delegations_[delegations_.length - 1].delegator, msg.sender, delegations_[delegationsIndex_] + ); + } + } } } diff --git a/src/enforcers/NativeTokenPaymentEnforcer.sol b/src/enforcers/NativeTokenPaymentEnforcer.sol index 40f8e04..f17f6fa 100644 --- a/src/enforcers/NativeTokenPaymentEnforcer.sol +++ b/src/enforcers/NativeTokenPaymentEnforcer.sol @@ -80,12 +80,16 @@ contract NativeTokenPaymentEnforcer is CaveatEnforcer { } } - bytes memory newEncodedContext_ = abi.encode(delegations_); - uint256 balanceBefore_ = recipient_.balance; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = Action({ to: recipient_, value: amount_, data: hex"" }); + // Attempt to redeem the delegation and make the payment - delegationManager.redeemDelegation(newEncodedContext_, Action({ to: recipient_, value: amount_, data: hex"" })); + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Ensure the recipient received the payment uint256 balanceAfter_ = recipient_.balance; diff --git a/src/interfaces/IDeleGatorCoreFull.sol b/src/interfaces/IDeleGatorCoreFull.sol index d005384..8e03d4f 100644 --- a/src/interfaces/IDeleGatorCoreFull.sol +++ b/src/interfaces/IDeleGatorCoreFull.sol @@ -29,7 +29,7 @@ interface IDeleGatorCoreFull is IDeleGatorCore, IERC165 { ////////////////////////////// MM Implementation Methods ////////////////////////////// - function redeemDelegation(bytes calldata _data, Action calldata _action) external; + function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external; function execute(Action calldata _action) external; diff --git a/src/interfaces/IDelegationManager.sol b/src/interfaces/IDelegationManager.sol index d71d6b8..1668b3b 100644 --- a/src/interfaces/IDelegationManager.sol +++ b/src/interfaces/IDelegationManager.sol @@ -33,9 +33,6 @@ interface IDelegationManager { /// @dev Error thrown when a user attempts to use a disabled delegation error CannotUseADisabledDelegation(); - /// @dev Error thrown when there are no delegations provided - error NoDelegationsProvided(); - /// @dev Error thrown when the authority in a chain of delegations doesn't match the expected authority error InvalidAuthority(); @@ -57,6 +54,9 @@ interface IDelegationManager { /// @dev Error thrown when the delegation provided is already enabled error AlreadyEnabled(); + /// @dev Error thrown when the batch size doesn't match the action array size + error BatchDataLengthMismatch(); + ////////////////////////////// MM Implementation Methods ////////////////////////////// function pause() external; @@ -71,7 +71,7 @@ interface IDelegationManager { function getDelegationHash(Delegation calldata _delegation) external pure returns (bytes32); - function redeemDelegation(bytes calldata _data, Action calldata _action) external; + function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external; function getDomainHash() external view returns (bytes32); } diff --git a/test/CounterfactualAssetsTest.t.sol b/test/CounterfactualAssetsTest.t.sol index 0611c0c..a14428a 100644 --- a/test/CounterfactualAssetsTest.t.sol +++ b/test/CounterfactualAssetsTest.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { BaseTest } from "./utils/BaseTest.t.sol"; -import { Delegation, Delegation, Caveat, Action } from "../src/utils/Types.sol"; +import { Delegation, Caveat, Action } from "../src/utils/Types.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { BasicCF721 } from "./utils/BasicCF721.t.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; diff --git a/test/DeleGatorTestSuite.t.sol b/test/DeleGatorTestSuite.t.sol index 8537a01..ec55f8b 100644 --- a/test/DeleGatorTestSuite.t.sol +++ b/test/DeleGatorTestSuite.t.sol @@ -252,10 +252,16 @@ abstract contract DeleGatorTestSuite is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + vm.expectRevert(abi.encodeWithSelector(IDelegationManager.EmptySignature.selector)); vm.prank(address(users.bob.deleGator)); - users.bob.deleGator.redeemDelegation(abi.encode(delegations_), action_); + users.bob.deleGator.redeemDelegation(encodedDelegations_, actions_); } // should not allow to enable already enabled delegation @@ -359,10 +365,14 @@ abstract contract DeleGatorTestSuite is BaseTest { // Create Bob's action Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); invokeDelegation_UserOp(users.bob, delegations_, action_); @@ -380,7 +390,7 @@ abstract contract DeleGatorTestSuite is BaseTest { ); bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); uint256[] memory signers_ = new uint256[](1); signers_[0] = users.bob.privateKey; @@ -531,7 +541,14 @@ abstract contract DeleGatorTestSuite is BaseTest { // Bob redeems the delegation vm.prank(users.bob.addr); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Validate that the count has increased by 1 updatedValue_ = aliceDeleGatorCounter.count(); @@ -582,7 +599,13 @@ abstract contract DeleGatorTestSuite is BaseTest { // Carol redeems the delegation vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Validate that the count has increased by 1 updatedValue_ = aliceDeleGatorCounter.count(); @@ -612,7 +635,13 @@ abstract contract DeleGatorTestSuite is BaseTest { vm.prank(users.bob.addr); vm.expectRevert(); - delegationManager.redeemDelegation(abi.encode("quack"), action_); + + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode("quack"); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -727,7 +756,14 @@ abstract contract DeleGatorTestSuite is BaseTest { delegations_[0] = delegation_; vm.prank(users.bob.addr); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -777,7 +813,14 @@ abstract contract DeleGatorTestSuite is BaseTest { delegations_[1] = delegation1_; vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -828,7 +871,14 @@ abstract contract DeleGatorTestSuite is BaseTest { vm.prank(users.carol.addr); vm.expectRevert(abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector)); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Get final count // Validate that the count has increased by 1 @@ -964,16 +1014,20 @@ abstract contract DeleGatorTestSuite is BaseTest { // Create Dave's action Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; // Execute Dave's UserOp Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = carolDelegation_; delegations_[1] = aliceDelegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); PackedUserOperation memory userOp_ = createAndSignUserOp( users.dave, address(users.dave.deleGator), - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_) + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_) ); PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); @@ -1087,7 +1141,14 @@ abstract contract DeleGatorTestSuite is BaseTest { delegations_[1] = aliceDelegation_; vm.prank(users.carol.addr); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1158,15 +1219,19 @@ abstract contract DeleGatorTestSuite is BaseTest { delegation_ = signDelegation(users.alice, delegation_); // Create Action - Action memory incrementAction_ = + Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; // Invoke delegation calldata Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); bytes memory invokeDelegationCalldata_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), incrementAction_); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); // Create invoke delegation Actions Action[] memory redemptionActions_ = new Action[](2); @@ -1205,12 +1270,15 @@ abstract contract DeleGatorTestSuite is BaseTest { // Invoke delegation calldata Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); - bytes memory invokeDelegationCalldata_ = abi.encodeWithSelector( - IDeleGatorCoreFull.redeemDelegation.selector, - abi.encode(delegations_), - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }) - ); + Action[] memory actions_ = new Action[](1); + actions_[0] = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + + bytes memory invokeDelegationCalldata_ = + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); // Create invoke delegation Actions Action[] memory redemptionActions_ = new Action[](2); @@ -1503,9 +1571,15 @@ abstract contract DeleGatorTestSuite is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + vm.prank(users.bob.addr); vm.expectRevert(); - delegationManager.redeemDelegation(abi.encode(delegations_), action_); + delegationManager.redeemDelegation(encodedDelegations_, actions_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1514,49 +1588,6 @@ abstract contract DeleGatorTestSuite is BaseTest { assertEq(finalValue_, initialValue_); } - // Should revert if user tries to redeem a delegation without providing delegations_ - function test_error_NoDelegationsProvided() public { - // Create delegation - Delegation memory delegation_ = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), - salt: 0, - signature: hex"" - }); - - delegation_ = signDelegation(users.alice, delegation_); - - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - Delegation[] memory delegations_ = new Delegation[](0); - - // creating userOpCallData_ - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); - - PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); - - PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); - userOps_[0] = userOp_; - - // prank from bundler - vm.prank(bundler); - - // get User Operation hash - bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); - - vm.expectEmit(true, true, false, true, address(entryPoint)); - // expected error - emit UserOperationRevertReason( - userOpHash_, address(users.bob.deleGator), 0, abi.encodeWithSelector(IDelegationManager.NoDelegationsProvided.selector) - ); - entryPoint.handleOps(userOps_, bundler); - } - // Should revert if the caller is not the delegate function test_error_InvalidDelegate() public { // Create delegation @@ -1574,13 +1605,17 @@ abstract contract DeleGatorTestSuite is BaseTest { // Create Bob's action Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); // create user operation calldata for invokeDelegation bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); PackedUserOperation memory userOp_ = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData_); @@ -1620,6 +1655,8 @@ abstract contract DeleGatorTestSuite is BaseTest { // Create Bob's action Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; // signing the userOp_ from bob uint256[] memory signers_ = new uint256[](1); @@ -1627,9 +1664,11 @@ abstract contract DeleGatorTestSuite is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); @@ -1669,13 +1708,17 @@ abstract contract DeleGatorTestSuite is BaseTest { // Create Bob's action Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); // create user operation calldata for invokeDelegation bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); // create and sign user operation with Bob PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); @@ -1756,10 +1799,15 @@ abstract contract DeleGatorTestSuite is BaseTest { Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = bobDelegation_; delegations_[1] = aliceDelegation_; + bytes[] memory encodedDelegations_ = new bytes[](1); + encodedDelegations_[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; // create user operation calldata for invokeDelegation bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); PackedUserOperation memory userOp_ = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData_); diff --git a/test/DelegationManagerTest.t.sol b/test/DelegationManagerTest.t.sol index ed7776c..00a23f4 100644 --- a/test/DelegationManagerTest.t.sol +++ b/test/DelegationManagerTest.t.sol @@ -7,14 +7,17 @@ import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; import { ShortStrings, ShortString } from "@openzeppelin/contracts/utils/ShortStrings.sol"; +import { Counter } from "./utils/Counter.t.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; -import { Delegation, Delegation, Caveat, Action } from "../src/utils/Types.sol"; +import { Delegation, Caveat, Action } from "../src/utils/Types.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; import { DelegationManager } from "../src/DelegationManager.sol"; import { Invalid1271Returns, Invalid1271Reverts } from "./utils/Invalid1271.t.sol"; import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; import { EIP712_DOMAIN_TYPEHASH } from "../src/utils/Typehashes.sol"; +import { MockCaveatEnforcer } from "./utils/MockCaveatEnforcer.sol"; +import { MockFailureCaveatEnforcer } from "./utils/MockFailureCaveatEnforcer.sol"; contract DelegationManagerTest is BaseTest { using ShortStrings for *; @@ -160,7 +163,14 @@ contract DelegationManagerTest is BaseTest { delegations_[0] = delegation_; vm.prank(address(users.bob.addr)); - delegationManager.redeemDelegation(abi.encode(delegations_), Action({ to: address(0), data: new bytes(0), value: 0 })); + + bytes[] memory dataArray = new bytes[](1); + dataArray[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = Action({ to: address(0), data: new bytes(0), value: 0 }); + + delegationManager.redeemDelegation(dataArray, actions_); } function test_notAllow_invalidSignatureReturns() public { @@ -181,7 +191,260 @@ contract DelegationManagerTest is BaseTest { delegations_[0] = delegation_; vm.prank(address(users.bob.addr)); - delegationManager.redeemDelegation(abi.encode(delegations_), Action({ to: address(0), data: new bytes(0), value: 0 })); + + bytes[] memory dataArray = new bytes[](1); + dataArray[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = Action({ to: address(0), data: new bytes(0), value: 0 }); + + delegationManager.redeemDelegation(dataArray, actions_); + } + + function test_allow_redeemBatchDelegation() public { + // Create a mock caveat enforcers contract + MockCaveatEnforcer mockEnforcer = new MockCaveatEnforcer(); + + // Create delegations with caveats + Delegation memory delegation1 = Delegation({ + delegate: address(users.bob.addr), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation1.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + Delegation memory delegation2 = Delegation({ + delegate: address(users.bob.addr), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation2.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + bytes[] memory permissionContexts = new bytes[](2); + + // Sign delegations + delegation1 = signDelegation(users.alice, delegation1); + delegation2 = signDelegation(users.alice, delegation2); + + Delegation[] memory delegations1 = new Delegation[](1); + delegations1[0] = delegation1; + permissionContexts[0] = abi.encode(delegations1); + + Delegation[] memory delegations2 = new Delegation[](1); + delegations2[0] = delegation2; + permissionContexts[1] = abi.encode(delegations2); + + Action[] memory actions = new Action[](2); + actions[0] = Action({ to: address(0), data: hex"", value: 0 }); + actions[1] = Action({ to: address(0), data: hex"", value: 0 }); + + vm.prank(address(users.bob.addr)); + delegationManager.redeemDelegation(permissionContexts, actions); + + // Assert that beforeHook was called for each action + assertEq(mockEnforcer.beforeHookCallCount(), 2); + + // Assert that afterHook was called after executing all actions + assertEq(mockEnforcer.afterHookCallCount(), 2); + } + + function test_allow_redeemBatchDelegationMixedWithNoDelegation() public { + Counter aliceDeleGatorCounter = new Counter(address(users.alice.deleGator)); + Counter bobDeleGatorCounter = new Counter(address(users.bob.deleGator)); + + // Create a mock caveat enforcers contract + MockCaveatEnforcer mockEnforcer = new MockCaveatEnforcer(); + + // Create delegations with caveats + Delegation memory delegation1 = Delegation({ + delegate: address(users.bob.deleGator), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation1.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + // Create delegations with caveats + Delegation memory delegation3 = Delegation({ + delegate: address(users.bob.deleGator), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation3.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + bytes[] memory permissionContexts = new bytes[](3); + + // Sign delegations + delegation1 = signDelegation(users.alice, delegation1); + delegation3 = signDelegation(users.alice, delegation3); + + Delegation[] memory delegations1 = new Delegation[](1); + delegations1[0] = delegation1; + permissionContexts[0] = abi.encode(delegations1); + + // This is an empty delegation for a self execution + Delegation[] memory delegations2 = new Delegation[](0); + permissionContexts[1] = abi.encode(delegations2); + + Delegation[] memory delegations3 = new Delegation[](1); + delegations3[0] = delegation3; + permissionContexts[2] = abi.encode(delegations3); + + Action memory incrementCounter_ = + Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Action[] memory actions = new Action[](3); + actions[0] = incrementCounter_; + actions[1] = + Action({ to: address(bobDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + actions[2] = incrementCounter_; + + assertEq(aliceDeleGatorCounter.count(), 0); + assertEq(bobDeleGatorCounter.count(), 0); + + vm.prank(address(users.bob.deleGator)); + delegationManager.redeemDelegation(permissionContexts, actions); + + // Assert that beforeHook was called for each action + assertEq(mockEnforcer.beforeHookCallCount(), 2); + + // Assert that afterHook was called after executing all actions + assertEq(mockEnforcer.afterHookCallCount(), 2); + + assertEq(aliceDeleGatorCounter.count(), 2); + assertEq(bobDeleGatorCounter.count(), 1); + } + + function test_allow_redeemBatchWithEoaInSecondBatchDelegation() public { + // Create a mock caveat enforcers contract + MockCaveatEnforcer mockEnforcer = new MockCaveatEnforcer(); + + // Create delegations with caveats + Delegation memory delegation1 = Delegation({ + delegate: address(users.carol.addr), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation1.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + Delegation memory delegation2 = Delegation({ + delegate: address(users.bob.addr), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation2.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + bytes32 delegation2Hash = delegationManager.getDelegationHash(delegation2); + + Delegation memory delegation3 = Delegation({ + delegate: address(users.carol.addr), + delegator: address(users.bob.addr), + authority: delegation2Hash, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation3.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + bytes[] memory permissionContexts = new bytes[](2); + + // Sign delegations + delegation1 = signDelegation(users.alice, delegation1); + delegation2 = signDelegation(users.alice, delegation2); + + // Sign a delegation with an EOA + bytes32 delegation3Hash = EncoderLib._getDelegationHash(delegation3); + bytes32 domainHash = delegationManager.getDomainHash(); + bytes32 typedData3Hash = MessageHashUtils.toTypedDataHash(domainHash, delegation3Hash); + delegation3.signature = signHash(SignatureType.EOA, users.bob, typedData3Hash); + + Delegation[] memory delegations1 = new Delegation[](1); + delegations1[0] = delegation1; + permissionContexts[0] = abi.encode(delegations1); + + Delegation[] memory delegations2 = new Delegation[](2); + delegations2[0] = delegation3; + delegations2[1] = delegation2; + permissionContexts[1] = abi.encode(delegations2); + + Action[] memory actions = new Action[](2); + actions[0] = Action({ to: address(0), data: hex"", value: 0 }); + actions[1] = Action({ to: address(0), data: hex"", value: 0 }); + + vm.prank(address(users.carol.addr)); + delegationManager.redeemDelegation(permissionContexts, actions); + + // Assert that beforeHook was called for each action + assertEq(mockEnforcer.beforeHookCallCount(), 3); + + // Assert that afterHook was called after executing all actions + assertEq(mockEnforcer.afterHookCallCount(), 3); + } + + // Should revert when any of the hooks revert + function test_revert_whenAnyCaveatHookFails() public { + // Create a mock caveat enforcers contract + MockCaveatEnforcer mockEnforcer = new MockCaveatEnforcer(); + MockFailureCaveatEnforcer mockFailureEnforcer = new MockFailureCaveatEnforcer(); + + // Create delegations with caveats + Delegation memory delegation1 = Delegation({ + delegate: address(users.bob.addr), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation1.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); + + Delegation memory delegation2 = Delegation({ + delegate: address(users.bob.addr), + delegator: address(users.alice.deleGator), + authority: ROOT_AUTHORITY, + caveats: new Caveat[](1), + salt: 0, + signature: hex"" + }); + delegation2.caveats[0] = Caveat({ enforcer: address(mockFailureEnforcer), terms: hex"", args: hex"" }); + + bytes[] memory permissionContexts = new bytes[](2); + + // Sign delegations + delegation1 = signDelegation(users.alice, delegation1); + delegation2 = signDelegation(users.alice, delegation2); + + Delegation[] memory delegations1 = new Delegation[](1); + delegations1[0] = delegation1; + permissionContexts[0] = abi.encode(delegations1); + + Delegation[] memory delegations2 = new Delegation[](1); + delegations2[0] = delegation2; + permissionContexts[1] = abi.encode(delegations2); + + Action[] memory actions_ = new Action[](2); + actions_[0] = Action({ to: address(0), data: hex"", value: 0 }); + actions_[1] = Action({ to: address(0), data: hex"", value: 0 }); + + vm.prank(address(users.bob.addr)); + vm.expectRevert(); + delegationManager.redeemDelegation(permissionContexts, actions_); } /////////////////////////////// Ownership ////////////////////////////// @@ -272,10 +535,13 @@ contract DelegationManagerTest is BaseTest { vm.startPrank(delegationManager.owner()); delegationManager.pause(); - Action memory action_; + Action[] memory actions_ = new Action[](1); + + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = hex""; vm.expectRevert(Pausable.EnforcedPause.selector); - delegationManager.redeemDelegation(hex"", action_); + delegationManager.redeemDelegation(permissionContexts_, actions_); } // Should fail to pause when the pause is active diff --git a/test/HybridDeleGatorTest.t.sol b/test/HybridDeleGatorTest.t.sol index fffc97d..a077971 100644 --- a/test/HybridDeleGatorTest.t.sol +++ b/test/HybridDeleGatorTest.t.sol @@ -10,7 +10,7 @@ import { BytesLib } from "@bytes-utils/BytesLib.sol"; import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; import { StorageUtilsLib } from "./utils/StorageUtilsLib.t.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; -import { Action, PackedUserOperation, Caveat, Delegation, Delegation } from "../src/utils/Types.sol"; +import { Action, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; import { HybridDeleGator } from "../src/HybridDeleGator.sol"; import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; diff --git a/test/InviteTest.t.sol b/test/InviteTest.t.sol index 9db5d8f..0a64ec0 100644 --- a/test/InviteTest.t.sol +++ b/test/InviteTest.t.sol @@ -172,8 +172,13 @@ contract InviteTest is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(delegations_), action_); + bytes[] memory dataArray = new bytes[](1); + dataArray[0] = abi.encode(delegations_); + + Action[] memory actions_ = new Action[](1); + actions_[0] = action_; + + bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, dataArray, actions_); PackedUserOperation memory userOp_ = createUserOp(predictedAddr_, userOpCallData_, initcode_); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(users.bob, userOpHash_.toEthSignedMessageHash()); diff --git a/test/MultiSigDeleGatorTest.t.sol b/test/MultiSigDeleGatorTest.t.sol index 7693f54..8351c51 100644 --- a/test/MultiSigDeleGatorTest.t.sol +++ b/test/MultiSigDeleGatorTest.t.sol @@ -10,7 +10,7 @@ import { ERC1967Proxy as DeleGatorProxy } from "@openzeppelin/contracts/proxy/ER import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; -import { Action, PackedUserOperation, Caveat, Delegation, Delegation } from "../src/utils/Types.sol"; +import { Action, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; import { AccountSorterLib } from "./utils/AccountSorterLib.t.sol"; import { MultiSigDeleGator } from "../src/MultiSigDeleGator.sol"; diff --git a/test/ProxyMigrationTest.t.sol b/test/ProxyMigrationTest.t.sol index e081816..2baaee1 100644 --- a/test/ProxyMigrationTest.t.sol +++ b/test/ProxyMigrationTest.t.sol @@ -10,7 +10,7 @@ import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/Mes import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; import { StorageUtilsLib } from "./utils/StorageUtilsLib.t.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; -import { Action, PackedUserOperation, Caveat, Delegation, Delegation } from "../src/utils/Types.sol"; +import { Action, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; import { HybridDeleGator } from "../src/HybridDeleGator.sol"; import { MultiSigDeleGator } from "../src/MultiSigDeleGator.sol"; diff --git a/test/enforcers/AllowedCalldataEnforcer.t.sol b/test/enforcers/AllowedCalldataEnforcer.t.sol index 0aa5725..93f3924 100644 --- a/test/enforcers/AllowedCalldataEnforcer.t.sol +++ b/test/enforcers/AllowedCalldataEnforcer.t.sol @@ -2,12 +2,11 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; -import "forge-std/console2.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { BytesLib } from "@bytes-utils/BytesLib.sol"; import { Counter } from "../utils/Counter.t.sol"; -import { Action, Caveat, Delegation, Delegation } from "../../src/utils/Types.sol"; +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { AllowedCalldataEnforcer } from "../../src/enforcers/AllowedCalldataEnforcer.sol"; import { IDelegationManager } from "../../src/interfaces/IDelegationManager.sol"; diff --git a/test/enforcers/AllowedMethodsEnforcer.t.sol b/test/enforcers/AllowedMethodsEnforcer.t.sol index d32dc90..1cd32f9 100644 --- a/test/enforcers/AllowedMethodsEnforcer.t.sol +++ b/test/enforcers/AllowedMethodsEnforcer.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { Action, Caveat, Delegation, Delegation } from "../../src/utils/Types.sol"; +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { AllowedMethodsEnforcer } from "../../src/enforcers/AllowedMethodsEnforcer.sol"; diff --git a/test/enforcers/AllowedTargetsEnforcer.t.sol b/test/enforcers/AllowedTargetsEnforcer.t.sol index 76304c0..3f35074 100644 --- a/test/enforcers/AllowedTargetsEnforcer.t.sol +++ b/test/enforcers/AllowedTargetsEnforcer.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; -import { Action, Caveat, Delegation, Delegation } from "../../src/utils/Types.sol"; +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { AllowedTargetsEnforcer } from "../../src/enforcers/AllowedTargetsEnforcer.sol"; diff --git a/test/enforcers/BlockNumberEnforcer.t.sol b/test/enforcers/BlockNumberEnforcer.t.sol index 1a4cf64..43c3f79 100644 --- a/test/enforcers/BlockNumberEnforcer.t.sol +++ b/test/enforcers/BlockNumberEnforcer.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Action, Caveat, Delegation, Delegation } from "../../src/utils/Types.sol"; +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { BlockNumberEnforcer } from "../../src/enforcers/BlockNumberEnforcer.sol"; diff --git a/test/enforcers/ERC20TransferAmountEnforcer.t.sol b/test/enforcers/ERC20TransferAmountEnforcer.t.sol index be52f45..d8f0572 100644 --- a/test/enforcers/ERC20TransferAmountEnforcer.t.sol +++ b/test/enforcers/ERC20TransferAmountEnforcer.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; -import { Action, Caveat, Delegation, Delegation } from "../../src/utils/Types.sol"; +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { ERC20TransferAmountEnforcer } from "../../src/enforcers/ERC20TransferAmountEnforcer.sol"; diff --git a/test/enforcers/NativeTokenPaymentEnforcer.t.sol b/test/enforcers/NativeTokenPaymentEnforcer.t.sol index c25457c..0fd3458 100644 --- a/test/enforcers/NativeTokenPaymentEnforcer.t.sol +++ b/test/enforcers/NativeTokenPaymentEnforcer.t.sol @@ -288,7 +288,6 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { function test_delegationFrontRunning() public { address recipient_ = address(users.alice.deleGator); - bytes memory paymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); // The original terms indicating to send 1 ether to Alice as the payment for Bob bytes memory originalPaymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); @@ -467,7 +466,7 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { /// @dev This contract is used for testing a case where the redeemDelegation() function doesn't work as expected contract MockDelegationManager { - function redeemDelegation(bytes calldata _data, Action calldata _action) external { + function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external { // Does not do anything, the action is not processed } } diff --git a/test/enforcers/TimestampEnforcer.t.sol b/test/enforcers/TimestampEnforcer.t.sol index a697506..2d6b2d6 100644 --- a/test/enforcers/TimestampEnforcer.t.sol +++ b/test/enforcers/TimestampEnforcer.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; -import { Action, Caveat, Delegation, Delegation } from "../../src/utils/Types.sol"; +import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { TimestampEnforcer } from "../../src/enforcers/TimestampEnforcer.sol"; diff --git a/test/utils/BaseTest.t.sol b/test/utils/BaseTest.t.sol index 8489261..e27fd9f 100644 --- a/test/utils/BaseTest.t.sol +++ b/test/utils/BaseTest.t.sol @@ -321,8 +321,14 @@ abstract contract BaseTest is Test { ) public { + bytes[] memory dataArray = new bytes[](1); + dataArray[0] = abi.encode(_delegations); + + Action[] memory actions_ = new Action[](1); + actions_[0] = _action; + bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, abi.encode(_delegations), _action); + abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, dataArray, actions_); PackedUserOperation memory userOp_ = createUserOp(address(_user.deleGator), userOpCallData_, _initCode); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(_user, userOpHash_.toEthSignedMessageHash()); diff --git a/test/utils/MockCaveatEnforcer.sol b/test/utils/MockCaveatEnforcer.sol new file mode 100644 index 0000000..c0d489f --- /dev/null +++ b/test/utils/MockCaveatEnforcer.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; +import { Action } from "../../src/utils/Types.sol"; + +/** + * @title MockCaveatEnforcer + * @dev This contract is a mock implementation of the ICaveatEnforcer interface for testing purposes. + */ +contract MockCaveatEnforcer is ICaveatEnforcer { + uint256 public beforeHookCallCount; + uint256 public afterHookCallCount; + + /** + * @dev Mocked implementation of the beforeHook function. + * Increments the beforeHook call count. + */ + function beforeHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external { + beforeHookCallCount++; + } + + /** + * @dev Mocked implementation of the afterHook function. + * Increments the afterHook call count. + */ + function afterHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external { + afterHookCallCount++; + } +} diff --git a/test/utils/MockFailureCaveatEnforcer.sol b/test/utils/MockFailureCaveatEnforcer.sol new file mode 100644 index 0000000..5eef1e1 --- /dev/null +++ b/test/utils/MockFailureCaveatEnforcer.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; +import { Action } from "../../src/utils/Types.sol"; + +/** + * @title MockFailureCaveatEnforcer + * @dev This contract is a mock implementation of the ICaveatEnforcer interface for testing purposes. + */ +contract MockFailureCaveatEnforcer is ICaveatEnforcer { + uint256 public beforeHookCallCount; + + /** + * @dev Mocked implementation of the beforeHook function. + * Increments the beforeHook call count. + */ + function beforeHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external { + beforeHookCallCount++; + } + + /** + * @dev Mocked implementation of the afterHook function. + * Increments the afterHook call count. + */ + function afterHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external pure { + revert(); + } +} From dc9bc0f19701df68c93fa42e433301807dfaa47b Mon Sep 17 00:00:00 2001 From: Dylan <13701258+dylandesrosier@users.noreply.github.com> Date: Sun, 18 Aug 2024 20:51:49 -0400 Subject: [PATCH 8/8] ERC7579 Execution Interface (#418) Co-authored-by: destroyersrt Co-authored-by: hanzel98 --- .gitmodules | 3 + lib/erc7579-implementation | 1 + remappings.txt | 3 +- src/DeleGatorCore.sol | 154 ++++- src/DelegationManager.sol | 84 +-- src/HybridDeleGator.sol | 2 +- src/MultiSigDeleGator.sol | 2 +- src/enforcers/AllowedCalldataEnforcer.sol | 22 +- src/enforcers/AllowedMethodsEnforcer.sol | 21 +- src/enforcers/AllowedTargetsEnforcer.sol | 19 +- src/enforcers/ArgsEqualityCheckEnforcer.sol | 5 +- src/enforcers/BlockNumberEnforcer.sol | 16 +- src/enforcers/CaveatEnforcer.sol | 29 +- src/enforcers/DeployedEnforcer.sol | 15 +- src/enforcers/ERC20BalanceGteEnforcer.sol | 11 +- src/enforcers/ERC20TransferAmountEnforcer.sol | 61 +- src/enforcers/IdEnforcer.sol | 5 +- src/enforcers/LimitedCallsEnforcer.sol | 5 +- src/enforcers/NativeBalanceGteEnforcer.sol | 11 +- src/enforcers/NativeTokenPaymentEnforcer.sol | 30 +- .../NativeTokenTransferAmountEnforcer.sol | 17 +- src/enforcers/NonceEnforcer.sol | 5 +- src/enforcers/RedeemerEnforcer.sol | 5 +- src/enforcers/TimestampEnforcer.sol | 16 +- src/enforcers/ValueLteEnforcer.sol | 22 +- src/interfaces/ICaveatEnforcer.sol | 20 +- src/interfaces/IDeleGatorCore.sol | 20 +- src/interfaces/IDeleGatorCoreFull.sol | 96 --- src/interfaces/IDelegationManager.sol | 11 +- src/libraries/EncoderLib.sol | 2 +- src/libraries/ExecutionLib.sol | 73 -- src/utils/{Typehashes.sol => Constants.sol} | 4 + src/utils/Types.sol | 15 +- test/CounterfactualAssetsTest.t.sol | 32 +- test/DeleGatorTestSuite.t.sol | 637 ++++++++++-------- test/DelegationManagerTest.t.sol | 170 ++--- test/HybridDeleGatorTest.t.sol | 104 +-- test/InviteTest.t.sol | 48 +- test/MultiSigDeleGatorTest.t.sol | 35 +- test/ProxyMigrationTest.t.sol | 55 +- test/enforcers/AllowedCalldataEnforcer.t.sol | 110 +-- test/enforcers/AllowedMethodsEnforcer.t.sol | 84 ++- test/enforcers/AllowedTargetsEnforcer.t.sol | 80 ++- .../enforcers/ArgsEqualityCheckEnforcer.t.sol | 13 +- test/enforcers/BlockNumberEnforcer.t.sol | 108 ++- test/enforcers/DeployedEnforcer.t.sol | 122 +++- test/enforcers/ERC20BalanceGteEnforcer.t.sol | 41 +- .../ERC20TransferAmountEnforcer.t.sol | 112 +-- test/enforcers/IdEnforcer.t.sol | 34 +- test/enforcers/LimitedCallsEnforcer.t.sol | 56 +- test/enforcers/NativeAllowanceEnforcer.t.sol | 45 +- test/enforcers/NativeBalanceGteEnforcer.t.sol | 36 +- .../NativeTokenPaymentEnforcer.t.sol | 116 +++- test/enforcers/NonceEnforcer.t.sol | 16 +- test/enforcers/PasswordEnforcer.t.sol | 52 +- test/enforcers/RedeemerEnforcer.t.sol | 60 +- test/enforcers/TimestampEnforcer.t.sol | 118 +++- test/enforcers/ValueLteEnforcer.t.sol | 36 +- test/metaTests/EncoderLibTest.t.sol | 2 +- test/metaTests/TypehashTest.t.sol | 2 +- test/utils/BaseTest.t.sol | 55 +- test/utils/Constants.sol | 6 + test/utils/MockCaveatEnforcer.sol | 6 +- test/utils/MockFailureCaveatEnforcer.sol | 6 +- test/utils/PasswordCaveatEnforcer.t.sol | 5 +- test/utils/Types.t.sol | 4 +- 66 files changed, 1891 insertions(+), 1320 deletions(-) create mode 160000 lib/erc7579-implementation delete mode 100644 src/interfaces/IDeleGatorCoreFull.sol delete mode 100644 src/libraries/ExecutionLib.sol rename src/utils/{Typehashes.sol => Constants.sol} (79%) create mode 100644 test/utils/Constants.sol diff --git a/.gitmodules b/.gitmodules index 3621929..f4e1d7d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "lib/account-abstraction"] path = lib/account-abstraction url = https://github.com/eth-infinitism/account-abstraction +[submodule "lib/erc7579-implementation"] + path = lib/erc7579-implementation + url = https://github.com/erc7579/erc7579-implementation diff --git a/lib/erc7579-implementation b/lib/erc7579-implementation new file mode 160000 index 0000000..42aa538 --- /dev/null +++ b/lib/erc7579-implementation @@ -0,0 +1 @@ +Subproject commit 42aa538397138e0858bae09d1bd1a1921aa24b8c diff --git a/remappings.txt b/remappings.txt index 10bde85..6ed7311 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,4 +5,5 @@ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ @solidity-stringutils/=lib/solidity-stringutils/src/ @bytes-utils/=lib/solidity-bytes-utils/contracts/ -@freshCryptoLib/=lib/FreshCryptoLib/solidity/src \ No newline at end of file +@freshCryptoLib/=lib/FreshCryptoLib/solidity/src/ +@erc7579/=lib/erc7579-implementation/src/ \ No newline at end of file diff --git a/src/DeleGatorCore.sol b/src/DeleGatorCore.sol index 71da3f6..3747b66 100644 --- a/src/DeleGatorCore.sol +++ b/src/DeleGatorCore.sol @@ -10,12 +10,15 @@ import { IERC1155Receiver } from "@openzeppelin/contracts/token/ERC1155/IERC1155 import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { ERC1967Utils } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; +import { ExecutionHelper } from "@erc7579/core/ExecutionHelper.sol"; import { ERC1271Lib } from "./libraries/ERC1271Lib.sol"; import { IDeleGatorCore } from "./interfaces/IDeleGatorCore.sol"; import { IDelegationManager } from "./interfaces/IDelegationManager.sol"; -import { Action, Delegation, PackedUserOperation } from "./utils/Types.sol"; -import { ExecutionLib } from "./libraries/ExecutionLib.sol"; +import { CallType, ExecType, Execution, Delegation, PackedUserOperation, ModeCode } from "./utils/Types.sol"; +import { CALLTYPE_SINGLE, CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXECTYPE_TRY } from "./utils/Constants.sol"; /** * @title DeleGatorCore @@ -24,8 +27,18 @@ import { ExecutionLib } from "./libraries/ExecutionLib.sol"; * @dev DeleGator implementations can inherit this to enable Delegation, ERC4337 and UUPS. * @dev DeleGator implementations MUST use Namespaced Storage to ensure subsequent UUPS implementation updates are safe. */ -abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDeleGatorCore, IERC721Receiver, IERC1155Receiver { +abstract contract DeleGatorCore is + Initializable, + ExecutionHelper, + UUPSUpgradeable, + IERC165, + IDeleGatorCore, + IERC721Receiver, + IERC1155Receiver +{ using MessageHashUtils for bytes32; + using ModeLib for ModeCode; + using ExecutionLib for bytes; ////////////////////////////// State ////////////////////////////// @@ -46,6 +59,9 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel /// @dev Emitted when the storage is cleared event ClearedStorage(); + /// @dev Event emitted when prefunding is sent. + event SentPrefund(address indexed sender, uint256 amount, bool success); + ////////////////////////////// Errors ////////////////////////////// /// @dev Error thrown when the caller is not this contract. @@ -60,6 +76,12 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel /// @dev Error thrown when the caller is not the delegation manager. error NotDelegationManager(); + /// @dev Error thrown when an execution with an unsupported CallType was made + error UnsupportedCallType(CallType callType); + + /// @dev Error thrown when an execution with an unsupported ExecType was made + error UnsupportedExecType(ExecType execType); + ////////////////////////////// Modifiers ////////////////////////////// /** @@ -112,39 +134,111 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel receive() external payable { } /** - * @notice Redeems a delegation on the DelegationManager and executes the specified actions on behalf of the root delegator. + * @notice Redeems a delegation on the DelegationManager and executes the specified executions on behalf of the root delegator. * @param _permissionContexts An array of bytes where each element is made up of an array - * of `Delegation` structs that are used to validate the authority given to execute the corresponding action on the + * of `Delegation` structs that are used to validate the authority given to execute the corresponding execution on the * root delegator, ordered from leaf to root. - * @param _actions An array of `Action` structs representing the actions to be executed. + * @param _modes An array of `ModeCode` structs representing the mode of execiton for each execution callData. + * @param _executionCallDatas An array of `Execution` structs representing the executions to be executed. */ - function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external onlyEntryPointOrSelf { - delegationManager.redeemDelegation(_permissionContexts, _actions); + function redeemDelegations( + bytes[] calldata _permissionContexts, + ModeCode[] calldata _modes, + bytes[] calldata _executionCallDatas + ) + external + onlyEntryPointOrSelf + { + delegationManager.redeemDelegations(_permissionContexts, _modes, _executionCallDatas); } - /// @inheritdoc IDeleGatorCore - function executeDelegatedAction(Action calldata _action) external onlyDelegationManager { - ExecutionLib._execute(_action); + /** + * @notice Executes an Execution from this contract + * @dev This method is intended to be called through a UserOp which ensures the invoker has sufficient permissions + * @dev This convenience method defeaults to reverting on failure and a single execution. + * @param _execution The Execution to be executed + */ + function execute(Execution calldata _execution) external payable onlyEntryPoint { + _execute(_execution.target, _execution.value, _execution.callData); } /** - * @notice Executes an Action from this contract + * @notice Executes an Execution from this contract + * @dev Related: @erc7579/MSAAdvanced.sol * @dev This method is intended to be called through a UserOp which ensures the invoker has sufficient permissions - * @dev This method reverts if the action fails. - * @param _action the action to execute + * @param _mode The ModeCode for the execution + * @param _executionCalldata The calldata for the execution */ - function execute(Action calldata _action) external onlyEntryPoint { - ExecutionLib._execute(_action); + function execute(ModeCode _mode, bytes calldata _executionCalldata) external payable onlyEntryPoint { + (CallType callType_, ExecType execType_,,) = _mode.decode(); + + // Check if calltype is batch or single + if (callType_ == CALLTYPE_BATCH) { + // destructure executionCallData according to batched exec + Execution[] calldata executions_ = _executionCalldata.decodeBatch(); + // Check if execType is revert or try + if (execType_ == EXECTYPE_DEFAULT) _execute(executions_); + else if (execType_ == EXECTYPE_TRY) _tryExecute(executions_); + else revert UnsupportedExecType(execType_); + } else if (callType_ == CALLTYPE_SINGLE) { + // Destructure executionCallData according to single exec + (address target_, uint256 value_, bytes calldata callData_) = _executionCalldata.decodeSingle(); + // Check if execType is revert or try + if (execType_ == EXECTYPE_DEFAULT) { + _execute(target_, value_, callData_); + } else if (execType_ == EXECTYPE_TRY) { + bytes[] memory returnData_ = new bytes[](1); + bool success_; + (success_, returnData_[0]) = _tryExecute(target_, value_, callData_); + if (!success_) emit TryExecuteUnsuccessful(0, returnData_[0]); + } else { + revert UnsupportedExecType(execType_); + } + } else { + revert UnsupportedCallType(callType_); + } } /** - * @notice This method executes several Actions in order. - * @dev This method is intended to be called through a UserOp which ensures the invoker has sufficient permissions. - * @dev This method reverts if any of the actions fail. - * @param _actions the ordered actions to execute + * @inheritdoc IDeleGatorCore + * @dev Related: @erc7579/MSAAdvanced.sol */ - function executeBatch(Action[] calldata _actions) external onlyEntryPointOrSelf { - ExecutionLib._executeBatch(_actions); + function executeFromExecutor( + ModeCode _mode, + bytes calldata _executionCalldata + ) + external + payable + onlyDelegationManager + returns (bytes[] memory returnData_) + { + (CallType callType_, ExecType execType_,,) = _mode.decode(); + + // Check if calltype is batch or single + if (callType_ == CALLTYPE_BATCH) { + // Destructure executionCallData according to batched exec + Execution[] calldata executions_ = _executionCalldata.decodeBatch(); + // check if execType is revert or try + if (execType_ == EXECTYPE_DEFAULT) returnData_ = _execute(executions_); + else if (execType_ == EXECTYPE_TRY) returnData_ = _tryExecute(executions_); + else revert UnsupportedExecType(execType_); + } else if (callType_ == CALLTYPE_SINGLE) { + // Destructure executionCallData according to single exec + (address target_, uint256 value_, bytes calldata callData_) = _executionCalldata.decodeSingle(); + returnData_ = new bytes[](1); + bool success_; + // check if execType is revert or try + if (execType_ == EXECTYPE_DEFAULT) { + returnData_[0] = _execute(target_, value_, callData_); + } else if (execType_ == EXECTYPE_TRY) { + (success_, returnData_[0]) = _tryExecute(target_, value_, callData_); + if (!success_) emit TryExecuteUnsuccessful(0, returnData_[0]); + } else { + revert UnsupportedExecType(execType_); + } + } else { + revert UnsupportedCallType(callType_); + } } /** @@ -166,7 +260,7 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel returns (uint256 validationData_) { validationData_ = _validateUserOpSignature(_userOp, _userOpHash); - ExecutionLib._payPrefund(_missingAccountFunds); + _payPrefund(_missingAccountFunds); } /** @@ -403,4 +497,18 @@ abstract contract DeleGatorCore is Initializable, UUPSUpgradeable, IERC165, IDel return 1; } } + + /** + * @notice Sends the entrypoint (msg.sender) any needed funds for the transaction. + * @param _missingAccountFunds the minimum value this method should send the entrypoint. + * this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster. + */ + function _payPrefund(uint256 _missingAccountFunds) internal { + if (_missingAccountFunds != 0) { + (bool success_,) = payable(msg.sender).call{ value: _missingAccountFunds, gas: type(uint256).max }(""); + (success_); + // Ignore failure (it's EntryPoint's job to verify, not account.) + emit SentPrefund(msg.sender, _missingAccountFunds, success_); + } + } } diff --git a/src/DelegationManager.sol b/src/DelegationManager.sol index c82f770..4f8889a 100644 --- a/src/DelegationManager.sol +++ b/src/DelegationManager.sol @@ -11,7 +11,7 @@ import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; import { ICaveatEnforcer } from "./interfaces/ICaveatEnforcer.sol"; import { IDelegationManager } from "./interfaces/IDelegationManager.sol"; import { IDeleGatorCore } from "./interfaces/IDeleGatorCore.sol"; -import { Action, Delegation, Caveat } from "./utils/Types.sol"; +import { Delegation, Caveat, ModeCode } from "./utils/Types.sol"; import { EncoderLib } from "./libraries/EncoderLib.sol"; import { ERC1271Lib } from "./libraries/ERC1271Lib.sol"; @@ -29,7 +29,7 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 string public constant NAME = "DelegationManager"; /// @dev The full version of the contract - string public constant VERSION = "1.0.0"; + string public constant VERSION = "1.1.0"; /// @dev The version used in the domainSeparator for EIP712 string public constant DOMAIN_VERSION = "1"; @@ -108,30 +108,39 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 } /** - * @notice This method validates the provided permission contexts and executes the action if the caller has authority to do so. + * @notice This method validates the provided permission contexts and executes the execution if the caller has authority to do + * so. * @dev The structure of the _permissionContexts array is determined by the specific Delegation Manager implementation - * If an entry in _permissionsContexts is empty (i.e., its length is 0), it is treated as a self-authorized action. - * @dev The length of _permissionsContexts must match the length of _actions. - * @dev The afterHook calls of all the caveat enforcers are called after the execution of all the actions in the batch. + * If an entry in _permissionsContexts is empty (i.e., its length is 0), it is treated as a self-authorized execution. + * @dev The length of _permissionsContexts must match the length of _executionCallDatas. + * @dev The afterHook calls of all the caveat enforcers are called after the execution of all the executions in the batch. * @dev If any afterHook fails, the entire transaction will revert. * @param _permissionContexts An array of bytes where each element is made up of an array - * of `Delegation` structs that are used to validate the authority given to execute the corresponding action on the + * of `Delegation` structs that are used to validate the authority given to execute the corresponding execution on the * root delegator, ordered from leaf to root. - * @param _actions the array of actions to be executed + * @param _modes the array of modes to execute the related execution callData + * @param _executionCallDatas the array of encoded executions to be executed */ - function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external whenNotPaused { + function redeemDelegations( + bytes[] calldata _permissionContexts, + ModeCode[] calldata _modes, + bytes[] calldata _executionCallDatas + ) + external + whenNotPaused + { uint256 batchSize_ = _permissionContexts.length; - if (batchSize_ != _actions.length) revert BatchDataLengthMismatch(); + if (batchSize_ != _executionCallDatas.length || batchSize_ != _modes.length) revert BatchDataLengthMismatch(); Delegation[][] memory batchDelegations_ = new Delegation[][](batchSize_); bytes32[][] memory batchDelegationHashes_ = new bytes32[][](batchSize_); - // Validate and process delegations for each action + // Validate and process delegations for each execution for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { Delegation[] memory delegations_ = abi.decode(_permissionContexts[batchIndex_], (Delegation[])); if (delegations_.length == 0) { - // Special case: If the permissionContext is empty, treat it as a self authorized action + // Special case: If the permissionContext is empty, treat it as a self authorized execution batchDelegations_[batchIndex_] = new Delegation[](0); batchDelegationHashes_[batchIndex_] = new bytes32[](0); } else { @@ -142,7 +151,9 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 batchDelegationHashes_[batchIndex_] = delegationHashes_; // Validate caller - if (delegations_[0].delegate != msg.sender && delegations_[0].delegate != ANY_DELEGATE) revert InvalidDelegate(); + if (delegations_[0].delegate != msg.sender && delegations_[0].delegate != ANY_DELEGATE) { + revert InvalidDelegate(); + } for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { Delegation memory delegation_ = delegations_[delegationsIndex_]; @@ -153,22 +164,19 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 revert EmptySignature(); } - // Check if the delegator is an EOA or a contract - address delegator_ = delegation_.delegator; - - if (delegator_.code.length == 0) { + if (delegation_.delegator.code.length == 0) { // Validate delegation if it's an EOA address result_ = ECDSA.recover( MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[delegationsIndex_]), delegation_.signature ); - if (result_ != delegator_) revert InvalidSignature(); + if (result_ != delegation_.delegator) revert InvalidSignature(); } else { // Validate delegation if it's a contract bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(getDomainHash(), delegationHashes_[delegationsIndex_]); - bytes32 result_ = IERC1271(delegator_).isValidSignature(typedDataHash_, delegation_.signature); + bytes32 result_ = IERC1271(delegation_.delegator).isValidSignature(typedDataHash_, delegation_.signature); if (result_ != ERC1271Lib.EIP1271_MAGIC_VALUE) { revert InvalidSignature(); } @@ -202,19 +210,18 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 // beforeHook (leaf to root) for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { if (batchDelegations_[batchIndex_].length > 0) { - Delegation[] memory delegations_ = batchDelegations_[batchIndex_]; - bytes32[] memory delegationHashes_ = batchDelegationHashes_[batchIndex_]; // Execute beforeHooks - for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { - Caveat[] memory caveats_ = delegations_[delegationsIndex_].caveats; + for (uint256 delegationsIndex_; delegationsIndex_ < batchDelegations_[batchIndex_].length; ++delegationsIndex_) { + Caveat[] memory caveats_ = batchDelegations_[batchIndex_][delegationsIndex_].caveats; for (uint256 caveatsIndex_; caveatsIndex_ < caveats_.length; ++caveatsIndex_) { ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[caveatsIndex_].enforcer); enforcer_.beforeHook( caveats_[caveatsIndex_].terms, caveats_[caveatsIndex_].args, - _actions[batchIndex_], - delegationHashes_[delegationsIndex_], - delegations_[delegationsIndex_].delegator, + _modes[batchIndex_], + _executionCallDatas[batchIndex_], + batchDelegationHashes_[batchIndex_][delegationsIndex_], + batchDelegations_[batchIndex_][delegationsIndex_].delegator, msg.sender ); } @@ -225,29 +232,29 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { if (batchDelegations_[batchIndex_].length == 0) { // special case: If there are no delegations, defer the call to the caller. - IDeleGatorCore(msg.sender).executeDelegatedAction(_actions[batchIndex_]); + IDeleGatorCore(msg.sender).executeFromExecutor(_modes[batchIndex_], _executionCallDatas[batchIndex_]); } else { IDeleGatorCore(batchDelegations_[batchIndex_][batchDelegations_[batchIndex_].length - 1].delegator) - .executeDelegatedAction(_actions[batchIndex_]); + .executeFromExecutor(_modes[batchIndex_], _executionCallDatas[batchIndex_]); } } // afterHook (root to leaf) for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { if (batchDelegations_[batchIndex_].length > 0) { - Delegation[] memory delegations_ = batchDelegations_[batchIndex_]; - bytes32[] memory delegationHashes_ = batchDelegationHashes_[batchIndex_]; // Execute afterHooks - for (uint256 delegationsIndex_ = delegations_.length; delegationsIndex_ > 0; --delegationsIndex_) { - Caveat[] memory caveats_ = delegations_[delegationsIndex_ - 1].caveats; + for (uint256 delegationsIndex_ = batchDelegations_[batchIndex_].length; delegationsIndex_ > 0; --delegationsIndex_) + { + Caveat[] memory caveats_ = batchDelegations_[batchIndex_][delegationsIndex_ - 1].caveats; for (uint256 caveatsIndex_; caveatsIndex_ < caveats_.length; ++caveatsIndex_) { ICaveatEnforcer enforcer_ = ICaveatEnforcer(caveats_[caveatsIndex_].enforcer); enforcer_.afterHook( caveats_[caveatsIndex_].terms, caveats_[caveatsIndex_].args, - _actions[batchIndex_], - delegationHashes_[delegationsIndex_ - 1], - delegations_[delegationsIndex_ - 1].delegator, + _modes[batchIndex_], + _executionCallDatas[batchIndex_], + batchDelegationHashes_[batchIndex_][delegationsIndex_ - 1], + batchDelegations_[batchIndex_][delegationsIndex_ - 1].delegator, msg.sender ); } @@ -257,10 +264,11 @@ contract DelegationManager is IDelegationManager, Ownable2Step, Pausable, EIP712 for (uint256 batchIndex_; batchIndex_ < batchSize_; ++batchIndex_) { if (batchDelegations_[batchIndex_].length > 0) { - Delegation[] memory delegations_ = batchDelegations_[batchIndex_]; - for (uint256 delegationsIndex_; delegationsIndex_ < delegations_.length; ++delegationsIndex_) { + for (uint256 delegationsIndex_; delegationsIndex_ < batchDelegations_[batchIndex_].length; ++delegationsIndex_) { emit RedeemedDelegation( - delegations_[delegations_.length - 1].delegator, msg.sender, delegations_[delegationsIndex_] + batchDelegations_[batchIndex_][batchDelegations_[batchIndex_].length - 1].delegator, + msg.sender, + batchDelegations_[batchIndex_][delegationsIndex_] ); } } diff --git a/src/HybridDeleGator.sol b/src/HybridDeleGator.sol index b062c43..39bd87f 100644 --- a/src/HybridDeleGator.sol +++ b/src/HybridDeleGator.sol @@ -30,7 +30,7 @@ contract HybridDeleGator is DeleGatorCore, IERC173 { ////////////////////////////// State ////////////////////////////// /// @dev The version of the contract - string public constant VERSION = "1.0.0"; + string public constant VERSION = "1.1.0"; /// @dev The storage location used for state /// @dev keccak256(abi.encode(uint256(keccak256("DeleGator.HybridDeleGator")) - 1)) & ~bytes32(uint256(0xff)) diff --git a/src/MultiSigDeleGator.sol b/src/MultiSigDeleGator.sol index b7d8cac..398aa40 100644 --- a/src/MultiSigDeleGator.sol +++ b/src/MultiSigDeleGator.sol @@ -25,7 +25,7 @@ contract MultiSigDeleGator is DeleGatorCore { ////////////////////////////// State ////////////////////////////// /// @dev The version of the contract - string public constant VERSION = "1.0.0"; + string public constant VERSION = "1.1.0"; /// @dev The storage slot for the MultiSig DeleGator /// @dev keccak256(abi.encode(uint256(keccak256("DeleGator.MultiSigDeleGator")) - 1)) & ~bytes32(uint256(0xff)) diff --git a/src/enforcers/AllowedCalldataEnforcer.sol b/src/enforcers/AllowedCalldataEnforcer.sol index df3dafe..4a89508 100644 --- a/src/enforcers/AllowedCalldataEnforcer.sol +++ b/src/enforcers/AllowedCalldataEnforcer.sol @@ -1,17 +1,22 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title AllowedCalldataEnforcer * @dev This contract enforces that some subset of the calldata to be executed matches the allowed subset of calldata. + * @dev This caveat enforcer only works when the execution is in single mode. * @dev A common use case for this enforcer is enforcing function parameters. It's strongly recommended to use this enforcer for * validating static types and not dynamic types. Ensuring that dynamic types are correct can be done through a series of * AllowedCalldataEnforcer terms but this is tedious and error-prone. */ contract AllowedCalldataEnforcer is CaveatEnforcer { + using ExecutionLib for bytes; + ////////////////////////////// Public Methods ////////////////////////////// /** @@ -20,12 +25,14 @@ contract AllowedCalldataEnforcer is CaveatEnforcer { * @param _terms This is packed bytes where: * - the first 32 bytes is the start of the subset of calldata bytes * - the remainder of the bytes is the expected value - * @param _action The action the delegate is trying try to execute. + * @param _mode The execution mode for the execution. + * @param _executionCallData The execution the delegate is trying try to execute. */ function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCallData, bytes32, address, address @@ -33,18 +40,19 @@ contract AllowedCalldataEnforcer is CaveatEnforcer { public pure override + onlySingleExecutionMode(_mode) { // Ensure that the first two term values are valid and at least 1 byte for value_ uint256 dataStart_; bytes memory value_; - bytes memory calldataValue_; + + (,, bytes calldata callData_) = _executionCallData.decodeSingle(); (dataStart_, value_) = getTermsInfo(_terms); uint256 valueLength_ = value_.length; - require(dataStart_ + valueLength_ <= _action.data.length, "AllowedCalldataEnforcer:invalid-calldata-length"); + require(dataStart_ + valueLength_ <= callData_.length, "AllowedCalldataEnforcer:invalid-calldata-length"); - calldataValue_ = _action.data[dataStart_:dataStart_ + valueLength_]; - require(_compare(calldataValue_, value_), "AllowedCalldataEnforcer:invalid-calldata"); + require(_compare(callData_[dataStart_:dataStart_ + valueLength_], value_), "AllowedCalldataEnforcer:invalid-calldata"); } /** diff --git a/src/enforcers/AllowedMethodsEnforcer.sol b/src/enforcers/AllowedMethodsEnforcer.sol index 8630f96..770b879 100644 --- a/src/enforcers/AllowedMethodsEnforcer.sol +++ b/src/enforcers/AllowedMethodsEnforcer.sol @@ -1,26 +1,34 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title AllowedMethodsEnforcer * @dev This contract enforces the allowed methods a delegate may call. + * @dev This caveat enforcer only works when the execution is in single mode. */ contract AllowedMethodsEnforcer is CaveatEnforcer { + using ExecutionLib for bytes; + ////////////////////////////// Public Methods ////////////////////////////// /** * @notice Allows the delegator to limit what methods the delegate may call. * @dev This function enforces the allowed methods before the transaction is performed. * @param _terms A series of 4byte method identifiers, representing the methods that the delegate is allowed to call. - * @param _action The transaction the delegate might try to perform. + * @param _mode The execution mode for the execution. + * @param _executionCallData The execution the delegate is trying try to execute. */ function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCallData, bytes32, address, address @@ -28,10 +36,13 @@ contract AllowedMethodsEnforcer is CaveatEnforcer { public pure override + onlySingleExecutionMode(_mode) { - require(_action.data.length >= 4, "AllowedMethodsEnforcer:invalid-action-data-length"); + (,, bytes calldata callData_) = _executionCallData.decodeSingle(); + + require(callData_.length >= 4, "AllowedMethodsEnforcer:invalid-execution-data-length"); - bytes4 targetSig_ = bytes4(_action.data[0:4]); + bytes4 targetSig_ = bytes4(callData_[0:4]); bytes4[] memory allowedSignatures_ = getTermsInfo(_terms); uint256 allowedSignaturesLength_ = allowedSignatures_.length; diff --git a/src/enforcers/AllowedTargetsEnforcer.sol b/src/enforcers/AllowedTargetsEnforcer.sol index 65fe04e..7ec281a 100644 --- a/src/enforcers/AllowedTargetsEnforcer.sol +++ b/src/enforcers/AllowedTargetsEnforcer.sol @@ -1,26 +1,33 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title AllowedTargetsEnforcer * @dev This contract enforces the allowed target addresses for a delegate. + * @dev This caveat enforcer only works when the execution is in single mode. */ contract AllowedTargetsEnforcer is CaveatEnforcer { + using ExecutionLib for bytes; + ////////////////////////////// Public Methods ////////////////////////////// /** * @notice Allows the delegator to limit what addresses the delegate may call. * @dev This function enforces the allowed target addresses before the transaction is performed. * @param _terms A series of 20byte addresses, representing the addresses that the delegate is allowed to call. - * @param _action The transaction the delegate might try to perform. + * @param _mode The execution mode for the execution. + * @param _executionCallData The execution the delegate is trying try to execute. */ function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCallData, bytes32, address, address @@ -28,12 +35,14 @@ contract AllowedTargetsEnforcer is CaveatEnforcer { public pure override + onlySingleExecutionMode(_mode) { - address targetAddress_ = _action.to; + (address target_,,) = _executionCallData.decodeSingle(); + address[] memory allowedTargets_ = getTermsInfo(_terms); uint256 allowedTargetsLength_ = allowedTargets_.length; for (uint256 i = 0; i < allowedTargetsLength_; ++i) { - if (targetAddress_ == allowedTargets_[i]) { + if (target_ == allowedTargets_[i]) { return; } } diff --git a/src/enforcers/ArgsEqualityCheckEnforcer.sol b/src/enforcers/ArgsEqualityCheckEnforcer.sol index e48cebc..60e7a56 100644 --- a/src/enforcers/ArgsEqualityCheckEnforcer.sol +++ b/src/enforcers/ArgsEqualityCheckEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * * @title ArgsEqualityCheckEnforcer @@ -31,7 +31,8 @@ contract ArgsEqualityCheckEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata _args, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address, address _redeemer diff --git a/src/enforcers/BlockNumberEnforcer.sol b/src/enforcers/BlockNumberEnforcer.sol index 3e3a58c..ebbf4b7 100644 --- a/src/enforcers/BlockNumberEnforcer.sol +++ b/src/enforcers/BlockNumberEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title BlockNumberEnforcer @@ -17,7 +17,19 @@ contract BlockNumberEnforcer is CaveatEnforcer { * @param _terms A bytes32 blocknumber range where the first half of the word is the earliest the delegation can be used and * the last half of the word is the latest the delegation can be used. The block number ranges are not inclusive. */ - function beforeHook(bytes calldata _terms, bytes calldata, Action calldata, bytes32, address, address) public view override { + function beforeHook( + bytes calldata _terms, + bytes calldata, + ModeCode, + bytes calldata, + bytes32, + address, + address + ) + public + view + override + { (uint128 blockAfterThreshold_, uint128 blockBeforeThreshold_) = getTermsInfo(_terms); if (blockAfterThreshold_ > 0) { diff --git a/src/enforcers/CaveatEnforcer.sol b/src/enforcers/CaveatEnforcer.sol index 4c816e9..84dbba0 100644 --- a/src/enforcers/CaveatEnforcer.sol +++ b/src/enforcers/CaveatEnforcer.sol @@ -1,17 +1,38 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; + import { ICaveatEnforcer } from "../interfaces/ICaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; +import { CALLTYPE_SINGLE, CALLTYPE_BATCH } from "../utils/Constants.sol"; /** * @title CaveatEnforcer - * @dev This abstract contract enforces caveats before and after the execution of an action. + * @dev This abstract contract enforces caveats before and after the execution of an execution. */ abstract contract CaveatEnforcer is ICaveatEnforcer { + using ModeLib for ModeCode; + /// @inheritdoc ICaveatEnforcer - function beforeHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) public virtual { } + function beforeHook(bytes calldata, bytes calldata, ModeCode, bytes calldata, bytes32, address, address) public virtual { } /// @inheritdoc ICaveatEnforcer - function afterHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) public virtual { } + function afterHook(bytes calldata, bytes calldata, ModeCode, bytes calldata, bytes32, address, address) public virtual { } + + /** + * @dev Require the function call to be in single execution mode + */ + modifier onlySingleExecutionMode(ModeCode _mode) { + require(ModeLib.getCallType(_mode) == CALLTYPE_SINGLE, "CaveatEnforcer:invalid-call-type"); + _; + } + + /** + * @dev Require the function call to be in batch execution mode + */ + modifier onlyBatchExecutionMode(ModeCode _mode) { + require(ModeLib.getCallType(_mode) == CALLTYPE_BATCH, "CaveatEnforcer:invalid-call-type"); + _; + } } diff --git a/src/enforcers/DeployedEnforcer.sol b/src/enforcers/DeployedEnforcer.sol index 7b8e4fa..d2c3647 100644 --- a/src/enforcers/DeployedEnforcer.sol +++ b/src/enforcers/DeployedEnforcer.sol @@ -5,7 +5,7 @@ import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Create2 } from "@openzeppelin/contracts/utils/Create2.sol"; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title DeployedEnforcer @@ -49,7 +49,18 @@ contract DeployedEnforcer is CaveatEnforcer { * the next 32 bytes are the salt to use for create2 * the remaining bytes are the bytecode of the contract to deploy */ - function beforeHook(bytes calldata _terms, bytes calldata, Action calldata, bytes32, address, address) public override { + function beforeHook( + bytes calldata _terms, + bytes calldata, + ModeCode, + bytes calldata, + bytes32, + address, + address + ) + public + override + { (address expectedAddress_, bytes32 salt_, bytes memory bytecode_) = getTermsInfo(_terms); // check if this contract has been deployed yet diff --git a/src/enforcers/ERC20BalanceGteEnforcer.sol b/src/enforcers/ERC20BalanceGteEnforcer.sol index bfe2269..b5e1197 100644 --- a/src/enforcers/ERC20BalanceGteEnforcer.sol +++ b/src/enforcers/ERC20BalanceGteEnforcer.sol @@ -4,12 +4,13 @@ pragma solidity 0.8.23; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title ERC20BalanceGteEnforcer * @dev This contract enforces that the delegator's ERC20 balance has increased by at least the specified amount - * after the action has been executed, measured between the `beforeHook` and `afterHook` calls, regardless of what the action is. + * after the execution has been executed, measured between the `beforeHook` and `afterHook` calls, regardless of what the execution + * is. * @dev This contract has no enforcement of how the balance increases. It's meant to be used alongside additional enforcers to * create granular permissions. */ @@ -42,7 +43,8 @@ contract ERC20BalanceGteEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address _delegator, address @@ -66,7 +68,8 @@ contract ERC20BalanceGteEnforcer is CaveatEnforcer { function afterHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address _delegator, address diff --git a/src/enforcers/ERC20TransferAmountEnforcer.sol b/src/enforcers/ERC20TransferAmountEnforcer.sol index 580c9db..6775a55 100644 --- a/src/enforcers/ERC20TransferAmountEnforcer.sol +++ b/src/enforcers/ERC20TransferAmountEnforcer.sol @@ -2,15 +2,19 @@ pragma solidity 0.8.23; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title ERC20TransferAmountEnforcer * @dev This contract enforces the transfer limit for ERC20 tokens. + * @dev This caveat enforcer only works when the execution is in single mode. */ contract ERC20TransferAmountEnforcer is CaveatEnforcer { + using ExecutionLib for bytes; + ////////////////////////////// State ////////////////////////////// mapping(address delegationManager => mapping(bytes32 delegationHash => uint256 amount)) public spentMap; @@ -27,36 +31,24 @@ contract ERC20TransferAmountEnforcer is CaveatEnforcer { * @dev This function enforces the transfer limit before the transaction is performed. * @param _terms The ERC20 token address, and the numeric maximum amount that the recipient may transfer on the signer's * behalf. - * @param _action The transaction the delegate might try to perform. + * @param _mode The mode of the execution. + * @param _executionCallData The transaction the delegate might try to perform. * @param _delegationHash The hash of the delegation being operated on. */ function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCallData, bytes32 _delegationHash, address, address _redeemer ) public override + onlySingleExecutionMode(_mode) { - require(_action.data.length == 68, "ERC20TransferAmountEnforcer:invalid-action-length"); - - (address allowedContract_, uint256 limit_) = getTermsInfo(_terms); - address targetContract_ = _action.to; - bytes4 allowedMethod_ = IERC20.transfer.selector; - - require(allowedContract_ == targetContract_, "ERC20TransferAmountEnforcer:invalid-contract"); - - bytes4 targetSig_ = bytes4(_action.data[0:4]); - require(targetSig_ == allowedMethod_, "ERC20TransferAmountEnforcer:invalid-method"); - - uint256 sending_ = uint256(bytes32(_action.data[36:68])); - - uint256 spent_ = spentMap[msg.sender][_delegationHash] += sending_; - require(spent_ <= limit_, "ERC20TransferAmountEnforcer:allowance-exceeded"); - + (uint256 limit_, uint256 spent_) = _validateAndIncrease(_terms, _executionCallData, _delegationHash); emit IncreasedSpentMap(msg.sender, _redeemer, _delegationHash, limit_, spent_); } @@ -72,4 +64,35 @@ contract ERC20TransferAmountEnforcer is CaveatEnforcer { allowedContract_ = address((bytes20(_terms[:20]))); maxTokens_ = uint256(bytes32(_terms[20:])); } + + /** + * @notice Returns the amount of tokens that the delegator has already spent. + * @param _terms The ERC20 token address, and the numeric maximum amount that the recipient may transfer + * @param _executionCallData The transaction the delegate might try to perform. + * @param _delegationHash The hash of the delegation being operated on. + * @return limit_ The maximum amount of tokens that the delegator is allowed to spend. + * @return spent_ The amount of tokens that the delegator has spent. + */ + function _validateAndIncrease( + bytes calldata _terms, + bytes calldata _executionCallData, + bytes32 _delegationHash + ) + internal + returns (uint256 limit_, uint256 spent_) + { + (address target_,, bytes calldata callData_) = _executionCallData.decodeSingle(); + + require(callData_.length == 68, "ERC20TransferAmountEnforcer:invalid-execution-length"); + + address allowedContract_; + (allowedContract_, limit_) = getTermsInfo(_terms); + + require(allowedContract_ == target_, "ERC20TransferAmountEnforcer:invalid-contract"); + + require(bytes4(callData_[0:4]) == IERC20.transfer.selector, "ERC20TransferAmountEnforcer:invalid-method"); + + spent_ = spentMap[msg.sender][_delegationHash] += uint256(bytes32(callData_[36:68])); + require(spent_ <= limit_, "ERC20TransferAmountEnforcer:allowance-exceeded"); + } } diff --git a/src/enforcers/IdEnforcer.sol b/src/enforcers/IdEnforcer.sol index ba092be..87b242a 100644 --- a/src/enforcers/IdEnforcer.sol +++ b/src/enforcers/IdEnforcer.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.23; import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title IdEnforcer Contract @@ -31,7 +31,8 @@ contract IdEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32, address _delegator, address _redeemer diff --git a/src/enforcers/LimitedCallsEnforcer.sol b/src/enforcers/LimitedCallsEnforcer.sol index fe53dfa..41684b4 100644 --- a/src/enforcers/LimitedCallsEnforcer.sol +++ b/src/enforcers/LimitedCallsEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title Limited Calls Enforcer Contract @@ -30,7 +30,8 @@ contract LimitedCallsEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address, address _redeemer diff --git a/src/enforcers/NativeBalanceGteEnforcer.sol b/src/enforcers/NativeBalanceGteEnforcer.sol index e599d8b..d965fba 100644 --- a/src/enforcers/NativeBalanceGteEnforcer.sol +++ b/src/enforcers/NativeBalanceGteEnforcer.sol @@ -2,12 +2,13 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title NativeBalanceGteEnforcer * @dev This contract enforces that a recipient's native token balance has increased by at least the specified amount - * after the action has been executed, measured between the `beforeHook` and `afterHook` calls, regardless of what the action is. + * after the execution has been executed, measured between the `beforeHook` and `afterHook` calls, regardless of what the execution + * is. * @dev This contract does not enforce how the balance increases. It is meant to be used with additional enforcers to create * granular permissions. */ @@ -40,7 +41,8 @@ contract NativeBalanceGteEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address, address @@ -65,7 +67,8 @@ contract NativeBalanceGteEnforcer is CaveatEnforcer { function afterHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address, address diff --git a/src/enforcers/NativeTokenPaymentEnforcer.sol b/src/enforcers/NativeTokenPaymentEnforcer.sol index f17f6fa..c6ff002 100644 --- a/src/enforcers/NativeTokenPaymentEnforcer.sol +++ b/src/enforcers/NativeTokenPaymentEnforcer.sol @@ -1,20 +1,26 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.23; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action, Delegation } from "../utils/Types.sol"; +import { Execution, Delegation, ModeCode } from "../utils/Types.sol"; import { IDelegationManager } from "../interfaces/IDelegationManager.sol"; /** * @title NativeTokenPaymentEnforcer * @notice This contract enforces payment in native token (e.g., ETH) for the right to use a delegation. - * @dev The redeemer must include a payment delegation in the arguments when executing an action. - * The payment, made in native token, is processed during the execution of the delegated action, ensuring that the + * @dev The redeemer must include a payment delegation in the arguments when executing an execution. + * The payment, made in native token, is processed during the execution of the delegated execution, ensuring that the * enforced conditions are met. * Combining `NativeTokenTransferAmountEnforcer` and `ArgsEqualityCheckEnforcer` when creating the payment delegation is recommended * to prevent front-running attacks. + * @dev Requires the redeemer to be a DeleGator that supports the single execution mode. */ contract NativeTokenPaymentEnforcer is CaveatEnforcer { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// /// @dev The Delegation Manager contract to redeem the delegation @@ -55,7 +61,8 @@ contract NativeTokenPaymentEnforcer is CaveatEnforcer { function afterHook( bytes calldata _terms, bytes calldata _args, - Action calldata, + ModeCode, + bytes calldata, bytes32 _delegationHash, address _delegator, address _redeemer @@ -80,16 +87,19 @@ contract NativeTokenPaymentEnforcer is CaveatEnforcer { } } - uint256 balanceBefore_ = recipient_.balance; + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(recipient_, amount_, hex""); - Action[] memory actions_ = new Action[](1); - actions_[0] = Action({ to: recipient_, value: amount_, data: hex"" }); + ModeCode[] memory encodedModes_ = new ModeCode[](1); + encodedModes_[0] = ModeLib.encodeSimpleSingle(); + + uint256 balanceBefore_ = recipient_.balance; // Attempt to redeem the delegation and make the payment - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, encodedModes_, executionCallDatas_); // Ensure the recipient received the payment uint256 balanceAfter_ = recipient_.balance; diff --git a/src/enforcers/NativeTokenTransferAmountEnforcer.sol b/src/enforcers/NativeTokenTransferAmountEnforcer.sol index 0665d31..a31016e 100644 --- a/src/enforcers/NativeTokenTransferAmountEnforcer.sol +++ b/src/enforcers/NativeTokenTransferAmountEnforcer.sol @@ -1,14 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.23; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title NativeTokenTransferAmountEnforcer * @notice This contract enforces an allowance of native currency (e.g., ETH) for a specific delegation. */ contract NativeTokenTransferAmountEnforcer is CaveatEnforcer { + using ExecutionLib for bytes; + ////////////////////////////// State ////////////////////////////// /// @notice Mapping to store used allowance for each delegation @@ -25,24 +29,29 @@ contract NativeTokenTransferAmountEnforcer is CaveatEnforcer { /** * @notice Enforces the conditions that should hold before a transaction is performed. * @param _terms The encoded amount of native token allowance. - * @param _action The action of the transaction. + * @param _mode The mode of the execution. + * @param _executionCallData The call data of the execution. * @param _delegationHash The hash of the delegation. */ function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCallData, bytes32 _delegationHash, address, address _redeemer ) public override + onlySingleExecutionMode(_mode) { // Decode the total allowance from _terms uint256 allowance_ = getTermsInfo(_terms); - uint256 spent_ = spentMap[msg.sender][_delegationHash] += _action.value; + (, uint256 value_,) = _executionCallData.decodeSingle(); + + uint256 spent_ = spentMap[msg.sender][_delegationHash] += value_; require(spent_ <= allowance_, "NativeTokenTransferAmountEnforcer:allowance-exceeded"); emit IncreasedSpentMap(msg.sender, _redeemer, _delegationHash, allowance_, spent_); diff --git a/src/enforcers/NonceEnforcer.sol b/src/enforcers/NonceEnforcer.sol index 5cfcbda..094a293 100644 --- a/src/enforcers/NonceEnforcer.sol +++ b/src/enforcers/NonceEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title Nonce Enforcer Contract @@ -27,7 +27,8 @@ contract NonceEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32, address _delegator, address diff --git a/src/enforcers/RedeemerEnforcer.sol b/src/enforcers/RedeemerEnforcer.sol index aea25d9..c6b0a0b 100644 --- a/src/enforcers/RedeemerEnforcer.sol +++ b/src/enforcers/RedeemerEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title RedeemerEnforcer @@ -21,7 +21,8 @@ contract RedeemerEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata, + ModeCode, + bytes calldata, bytes32, address, address _redeemer diff --git a/src/enforcers/TimestampEnforcer.sol b/src/enforcers/TimestampEnforcer.sol index 345efcd..a272c21 100644 --- a/src/enforcers/TimestampEnforcer.sol +++ b/src/enforcers/TimestampEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title Timestamp Enforcer Contract @@ -17,7 +17,19 @@ contract TimestampEnforcer is CaveatEnforcer { * @param _terms - A bytes32 timestamp range where the first half of the word is the earliest the delegation can be used and the * last half of the word is the latest the delegation can be used. The timestamp ranges are not inclusive. */ - function beforeHook(bytes calldata _terms, bytes calldata, Action calldata, bytes32, address, address) public view override { + function beforeHook( + bytes calldata _terms, + bytes calldata, + ModeCode, + bytes calldata, + bytes32, + address, + address + ) + public + view + override + { (uint128 timestampAfterThreshold_, uint128 timestampBeforeThreshold_) = getTermsInfo(_terms); if (timestampAfterThreshold_ > 0) { diff --git a/src/enforcers/ValueLteEnforcer.sol b/src/enforcers/ValueLteEnforcer.sol index c2b0584..929d027 100644 --- a/src/enforcers/ValueLteEnforcer.sol +++ b/src/enforcers/ValueLteEnforcer.sol @@ -1,25 +1,31 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + import { CaveatEnforcer } from "./CaveatEnforcer.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title ValueLteEnforcer - * @dev This contract extends the CaveatEnforcer contract. It provides functionality to enforce a specific value for the Action + * @dev This contract extends the CaveatEnforcer contract. It provides functionality to enforce a specific value for the Execution * being executed. + * @dev This caveat enforcer only works when the execution is in single mode. */ contract ValueLteEnforcer is CaveatEnforcer { + using ExecutionLib for bytes; + ////////////////////////////// Public Methods ////////////////////////////// /** * @notice Allows the delegator to specify a maximum value of native tokens that the delegate can spend. - * @param _terms - A uint256 value that the Action's value must be less than or equal to. + * @param _terms - A uint256 value that the Execution's value must be less than or equal to. */ function beforeHook( bytes calldata _terms, bytes calldata, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCallData, bytes32, address, address @@ -27,15 +33,17 @@ contract ValueLteEnforcer is CaveatEnforcer { public pure override + onlySingleExecutionMode(_mode) { - uint256 value_ = getTermsInfo(_terms); - require(_action.value <= value_, "ValueLteEnforcer:value-too-high"); + (, uint256 value_,) = _executionCallData.decodeSingle(); + uint256 termsValue_ = getTermsInfo(_terms); + require(value_ <= termsValue_, "ValueLteEnforcer:value-too-high"); } /** * @notice Decodes the terms used in this CaveatEnforcer. * @param _terms encoded data that is used during the execution hooks. - * @return value_ The value that the Action's value must be less than or equal to. + * @return value_ The value that the Execution's value must be less than or equal to. */ function getTermsInfo(bytes calldata _terms) public pure returns (uint256 value_) { require(_terms.length == 32, "ValueLteEnforcer:invalid-terms-length"); diff --git a/src/interfaces/ICaveatEnforcer.sol b/src/interfaces/ICaveatEnforcer.sol index 83c4e69..0b5802f 100644 --- a/src/interfaces/ICaveatEnforcer.sol +++ b/src/interfaces/ICaveatEnforcer.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title CaveatEnforcer - * @notice This is an abstract contract that exposes pre and post Action hooks during delegation redemption. - * @dev Hooks can be used to enforce conditions before and after an Action is performed. + * @notice This is an abstract contract that exposes pre and post Execution hooks during delegation redemption. + * @dev Hooks can be used to enforce conditions before and after an Execution is performed. * @dev Reverting during the hooks will revert the entire delegation redemption. * @dev Child contracts can implement the beforeHook method and/or afterHook method. - * @dev NOTE: There is no guarantee that the action is executed. If you are relying on the action then be sure to use the + * @dev NOTE: There is no guarantee that the execution is executed. If you are relying on the execution then be sure to use the * `afterHook` method. */ interface ICaveatEnforcer { @@ -18,7 +18,8 @@ interface ICaveatEnforcer { * @dev This function MUST revert if the conditions are not met. * @param _terms The terms to enforce set by the delegator. * @param _args An optional input parameter set by the redeemer at time of invocation. - * @param _action The action of the transaction. + * @param _mode The mode of execution for the executionCalldata. + * @param _executionCalldata The data representing the execution. * @param _delegationHash The hash of the delegation. * @param _delegator The address of the delegator. * @param _redeemer The address that is redeeming the delegation. @@ -26,7 +27,8 @@ interface ICaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata _args, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCalldata, bytes32 _delegationHash, address _delegator, address _redeemer @@ -38,7 +40,8 @@ interface ICaveatEnforcer { * @dev This function MUST revert if the conditions are not met. * @param _terms The terms to enforce set by the delegator. * @param _args An optional input parameter set by the redeemer at time of invocation. - * @param _action The action of the transaction. + * @param _mode The mode of execution for the executionCalldata. + * @param _executionCalldata The data representing the execution. * @param _delegationHash The hash of the delegation. * @param _delegator The address of the delegator. * @param _redeemer The address that is redeeming the delegation. @@ -46,7 +49,8 @@ interface ICaveatEnforcer { function afterHook( bytes calldata _terms, bytes calldata _args, - Action calldata _action, + ModeCode _mode, + bytes calldata _executionCalldata, bytes32 _delegationHash, address _delegator, address _redeemer diff --git a/src/interfaces/IDeleGatorCore.sol b/src/interfaces/IDeleGatorCore.sol index 3696058..9790052 100644 --- a/src/interfaces/IDeleGatorCore.sol +++ b/src/interfaces/IDeleGatorCore.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; -import { Action } from "../utils/Types.sol"; +import { ModeCode } from "../utils/Types.sol"; /** * @title IDeleGatorCore @@ -11,9 +11,19 @@ import { Action } from "../utils/Types.sol"; */ interface IDeleGatorCore is IERC1271 { /** - * @notice executes a CALL using the data provided in the action - * @dev MUST enforce calls come from an approved DelegationManager address - * @param _action the onchain action to perform + * @dev Executes a transaction on behalf of the account. + * This function is intended to be called by Executor Modules + * @dev Ensure adequate authorization control: i.e. onlyExecutorModule + * @dev If a mode is requested that is not supported by the Account, it MUST revert + * @dev Related: @erc7579/MSAAdvanced.sol + * @param _mode The encoded execution mode of the transaction. See @erc7579/ModeLib.sol for details. + * @param _executionCalldata The encoded execution call data */ - function executeDelegatedAction(Action calldata _action) external; + function executeFromExecutor( + ModeCode _mode, + bytes calldata _executionCalldata + ) + external + payable + returns (bytes[] memory returnData); } diff --git a/src/interfaces/IDeleGatorCoreFull.sol b/src/interfaces/IDeleGatorCoreFull.sol deleted file mode 100644 index 8e03d4f..0000000 --- a/src/interfaces/IDeleGatorCoreFull.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: MIT AND Apache-2.0 -pragma solidity 0.8.23; - -import { IEntryPoint } from "@account-abstraction/interfaces/IEntryPoint.sol"; -import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - -import { IDeleGatorCore } from "./IDeleGatorCore.sol"; -import { IDelegationManager } from "./IDelegationManager.sol"; -import { Action, Delegation, PackedUserOperation } from "../utils/Types.sol"; - -/** - * @title IDeleGatorCoreFull - * @notice Interface for a DeleGator that exposes the minimal functionality required. - */ -interface IDeleGatorCoreFull is IDeleGatorCore, IERC165 { - ////////////////////////////// Events ////////////////////////////// - event SetDelegationManager(IDelegationManager indexed newDelegationManager); - - event SetEntryPoint(IEntryPoint indexed entryPoint); - - event ClearedStorage(); - - ////////////////////////////// Errors ////////////////////////////// - - error NotSelf(); - error NotEntryPoint(); - error NotEntryPointOrSelf(); - error NotDelegationManager(); - - ////////////////////////////// MM Implementation Methods ////////////////////////////// - - function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external; - - function execute(Action calldata _action) external; - - function executeBatch(Action[] calldata _actions) external; - - function validateUserOp( - PackedUserOperation calldata _userOp, - bytes32 _userOpHash, - uint256 _missingAccountFunds - ) - external - returns (uint256 validationData_); - - function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4 magicValue_); - - function addDeposit() external payable; - - function withdrawDeposit(address payable _withdrawAddress, uint256 _withdrawAmount) external; - - function disableDelegation(Delegation calldata _delegation) external; - - function enableDelegation(Delegation calldata _delegation) external; - - function upgradeToAndCall(address _newImplementation, bytes memory _data) external payable; - - function upgradeToAndCallAndRetainStorage(address _newImplementation, bytes memory _data) external payable; - - function isDelegationDisabled(bytes32 _delegationHash) external view returns (bool); - - function entryPoint() external view returns (IEntryPoint); - - function delegationManager() external view returns (IDelegationManager); - - function getNonce() external view returns (uint256); - - function getNonce(uint192 _key) external view returns (uint256); - - function getDeposit() external view returns (uint256); - - function getImplementation() external view returns (address); - - function getInitializedVersion() external view returns (uint64); - - ////////////////////////////// TokenCallbackHandler Methods ////////////////////////////// - - function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4); - - function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4); - - function onERC1155BatchReceived( - address, - address, - uint256[] calldata, - uint256[] calldata, - bytes calldata - ) - external - pure - returns (bytes4); - - ////////////////////////////// UUPSUpgradeable Methods ////////////////////////////// - - function proxiableUUID() external view returns (bytes32); -} diff --git a/src/interfaces/IDelegationManager.sol b/src/interfaces/IDelegationManager.sol index 1668b3b..0435a8e 100644 --- a/src/interfaces/IDelegationManager.sol +++ b/src/interfaces/IDelegationManager.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; -import { Action, Delegation } from "../utils/Types.sol"; +import { Delegation, Execution, ModeCode } from "../utils/Types.sol"; /** * @title IDelegationManager @@ -54,7 +54,7 @@ interface IDelegationManager { /// @dev Error thrown when the delegation provided is already enabled error AlreadyEnabled(); - /// @dev Error thrown when the batch size doesn't match the action array size + /// @dev Error thrown when the batch size doesn't match the execution array size error BatchDataLengthMismatch(); ////////////////////////////// MM Implementation Methods ////////////////////////////// @@ -71,7 +71,12 @@ interface IDelegationManager { function getDelegationHash(Delegation calldata _delegation) external pure returns (bytes32); - function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external; + function redeemDelegations( + bytes[] calldata _permissionContexts, + ModeCode[] calldata _modes, + bytes[] calldata _executionCallDatas + ) + external; function getDomainHash() external view returns (bytes32); } diff --git a/src/libraries/EncoderLib.sol b/src/libraries/EncoderLib.sol index 0477515..fb97745 100644 --- a/src/libraries/EncoderLib.sol +++ b/src/libraries/EncoderLib.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { Delegation, Caveat } from "../utils/Types.sol"; -import { DELEGATION_TYPEHASH, CAVEAT_TYPEHASH } from "../utils/Typehashes.sol"; +import { DELEGATION_TYPEHASH, CAVEAT_TYPEHASH } from "../utils/Constants.sol"; /** * @dev Provides implementations for common utility methods for Delegation. diff --git a/src/libraries/ExecutionLib.sol b/src/libraries/ExecutionLib.sol deleted file mode 100644 index e5c1a3a..0000000 --- a/src/libraries/ExecutionLib.sol +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: MIT AND Apache-2.0 -pragma solidity 0.8.23; - -import { Action } from "../utils/Types.sol"; - -/** - * @title Execution Library - * Provides a common implementation for executing actions. - */ -library ExecutionLib { - ////////////////////////////// Errors ////////////////////////////// - - /// @dev Error thrown when execution fails without providing a reason - error FailedExecutionWithoutReason(); - - /// @dev Error thrown when executing empty Actions array - error InvalidActionsLength(); - - ////////////////////////////// Events ////////////////////////////// - - /// @dev Event emitted when an action is executed. - event ExecutedAction(address indexed to, uint256 value, bool success, bytes errorMessage); - - /// @dev Event emitted when prefunding is sent. - event SentPrefund(address indexed sender, uint256 amount, bool success); - - ////////////////////////////// Internal Functions ////////////////////////////// - - /** - * @notice Executes the provided Action and reverts if the execution fails. - * @dev Ensure caller permissions are checked before calling this method - * @param _action the Action to execute - */ - function _execute(Action calldata _action) internal { - (bool success_, bytes memory errorMessage_) = _action.to.call{ value: _action.value }(_action.data); - - emit ExecutedAction(_action.to, _action.value, success_, errorMessage_); - - if (!success_) { - if (errorMessage_.length == 0) revert FailedExecutionWithoutReason(); - - assembly { - revert(add(32, errorMessage_), mload(errorMessage_)) - } - } - } - - /** - * @notice Executes several Actions in order and reverts if any of the executions fail. - * @param _actions the ordered actions to execute - */ - function _executeBatch(Action[] calldata _actions) internal { - uint256 actionLength = _actions.length; - if (actionLength == 0) revert InvalidActionsLength(); - for (uint256 i = 0; i < actionLength; ++i) { - _execute(_actions[i]); - } - } - - /** - * @notice Sends the entrypoint (msg.sender) any needed funds for the transaction. - * @param _missingAccountFunds the minimum value this method should send the entrypoint. - * this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster. - */ - function _payPrefund(uint256 _missingAccountFunds) internal { - if (_missingAccountFunds != 0) { - (bool success_,) = payable(msg.sender).call{ value: _missingAccountFunds, gas: type(uint256).max }(""); - (success_); - //ignore failure (its EntryPoint's job to verify, not account.) - emit SentPrefund(msg.sender, _missingAccountFunds, success_); - } - } -} diff --git a/src/utils/Typehashes.sol b/src/utils/Constants.sol similarity index 79% rename from src/utils/Typehashes.sol rename to src/utils/Constants.sol index 019d50f..9dab2ac 100644 --- a/src/utils/Typehashes.sol +++ b/src/utils/Constants.sol @@ -1,6 +1,10 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { + CALLTYPE_SINGLE, CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXECTYPE_TRY, MODE_DEFAULT, MODE_OFFSET +} from "@erc7579/lib/ModeLib.sol"; + bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); diff --git a/src/utils/Types.sol b/src/utils/Types.sol index c75f000..50bff06 100644 --- a/src/utils/Types.sol +++ b/src/utils/Types.sol @@ -2,6 +2,8 @@ pragma solidity 0.8.23; import { PackedUserOperation } from "@account-abstraction/interfaces/PackedUserOperation.sol"; +import { Execution } from "@erc7579/interfaces/IERC7579Account.sol"; +import { ModeCode, CallType, ExecType, ModeSelector, ModePayload } from "@erc7579/lib/ModeLib.sol"; /** * @title EIP712Domain @@ -39,19 +41,6 @@ struct Caveat { bytes args; } -/** - * @title Action - * @notice This struct represents an action to be taken. - * @dev It is used to pass the action of a transaction to a CaveatEnforcer. - * It only includes the functional part of a transaction, allowing it to be - * agnostic whether this was sent from a protocol-level tx or UserOperation. - */ -struct Action { - address to; - uint256 value; - bytes data; -} - /** * @title P256 Public Key * @notice Struct containing the X and Y coordinates of a P256 public key. diff --git a/test/CounterfactualAssetsTest.t.sol b/test/CounterfactualAssetsTest.t.sol index a14428a..f661ea1 100644 --- a/test/CounterfactualAssetsTest.t.sol +++ b/test/CounterfactualAssetsTest.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { BaseTest } from "./utils/BaseTest.t.sol"; -import { Delegation, Caveat, Action } from "../src/utils/Types.sol"; +import { Delegation, Caveat, Execution } from "../src/utils/Types.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { BasicCF721 } from "./utils/BasicCF721.t.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; @@ -83,17 +83,17 @@ contract CounterfactualAssetsTest is BaseTest { // Alice signs Delegation to deploy BasicCF721 delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action_ to mint an NFT - Action memory action_ = Action({ - to: predictedAddr_, + // Create Bob's execution_ to mint an NFT + Execution memory execution_ = Execution({ + target: predictedAddr_, value: 0, - data: abi.encodeWithSelector(BasicCF721.mint.selector, [address(users.bob.deleGator)]) + callData: abi.encodeWithSelector(BasicCF721.mint.selector, [address(users.bob.deleGator)]) }); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final state bytes memory finalCode_ = predictedAddr_.code; @@ -153,17 +153,17 @@ contract CounterfactualAssetsTest is BaseTest { // Alice signs Delegation to deploy BasicCF721 delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action_ to mint an NFT - Action memory action_ = Action({ - to: predictedAddr_, + // Create Bob's execution_ to mint an NFT + Execution memory execution_ = Execution({ + target: predictedAddr_, value: 0, - data: abi.encodeWithSelector(BasicCF721.mint.selector, [address(users.bob.deleGator)]) + callData: abi.encodeWithSelector(BasicCF721.mint.selector, [address(users.bob.deleGator)]) }); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final state bytes memory finalCode_ = predictedAddr_.code; @@ -237,18 +237,18 @@ contract CounterfactualAssetsTest is BaseTest { // Bob signs Delegation to Carol bobDelegation_ = signDelegation(users.bob, bobDelegation_); - // Create Carols's action_ to mint an NFT - Action memory action_ = Action({ - to: predictedAddr_, + // Create Carols's execution_ to mint an NFT + Execution memory execution_ = Execution({ + target: predictedAddr_, value: 0, - data: abi.encodeWithSelector(BasicCF721.mint.selector, [address(users.carol.deleGator)]) + callData: abi.encodeWithSelector(BasicCF721.mint.selector, [address(users.carol.deleGator)]) }); // Execute Carol's UserOp Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = bobDelegation_; delegations_[1] = aliceDelegation_; - invokeDelegation_UserOp(users.carol, delegations_, action_); + invokeDelegation_UserOp(users.carol, delegations_, execution_); // Get final state bytes memory finalCode_ = predictedAddr_.code; diff --git a/test/DeleGatorTestSuite.t.sol b/test/DeleGatorTestSuite.t.sol index ec55f8b..ffbbd30 100644 --- a/test/DeleGatorTestSuite.t.sol +++ b/test/DeleGatorTestSuite.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import { IEntryPoint, EntryPoint } from "@account-abstraction/core/EntryPoint.sol"; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; @@ -9,29 +10,32 @@ import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { UUPSUpgradeable } from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionHelper } from "@erc7579/core/ExecutionHelper.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; -import { Delegation, Caveat, PackedUserOperation, Delegation, Action } from "../src/utils/Types.sol"; +import { Delegation, Caveat, PackedUserOperation, Delegation, Execution, ModeCode } from "../src/utils/Types.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { Counter } from "./utils/Counter.t.sol"; import { StorageUtilsLib } from "./utils/StorageUtilsLib.t.sol"; import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; -import { ExecutionLib } from "../src/libraries/ExecutionLib.sol"; - -import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; +import { EXECUTE_SINGULAR_SIGNATURE } from "./utils/Constants.sol"; import { IDeleGatorCore } from "../src/interfaces/IDeleGatorCore.sol"; -import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; +import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; +import { DeleGatorCore } from "../src/DeleGatorCore.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; import { AllowedMethodsEnforcer } from "../src/enforcers/AllowedMethodsEnforcer.sol"; import { AllowedTargetsEnforcer } from "../src/enforcers/AllowedTargetsEnforcer.sol"; abstract contract DeleGatorTestSuite is BaseTest { + using ModeLib for ModeCode; using MessageHashUtils for bytes32; ////////////////////////////// Setup ////////////////////// Counter aliceDeleGatorCounter; Counter bobDeleGatorCounter; + ModeCode[] oneSingularMode; function setUp() public virtual override { super.setUp(); @@ -43,6 +47,9 @@ abstract contract DeleGatorTestSuite is BaseTest { aliceDeleGatorCounter = new Counter(address(users.alice.deleGator)); bobDeleGatorCounter = new Counter(address(users.bob.deleGator)); + + oneSingularMode = new ModeCode[](1); + oneSingularMode[0] = ModeLib.encodeSimpleSingle(); } ////////////////////////////// State ////////////////////////////// @@ -78,7 +85,6 @@ abstract contract DeleGatorTestSuite is BaseTest { uint256 actualGasUsed ); event Withdrawn(address indexed account, address withdrawAddress, uint256 amount); - event ExecutedAction(address indexed to, uint256 value, bool success, bytes errorMessage); event SentPrefund(address indexed sender, uint256 amount, bool success); event RedeemedDelegation(address indexed rootDelegator, address indexed redeemer, Delegation delegation); @@ -246,22 +252,25 @@ abstract contract DeleGatorTestSuite is BaseTest { signature: hex"" }); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); vm.expectRevert(abi.encodeWithSelector(IDelegationManager.EmptySignature.selector)); vm.prank(address(users.bob.deleGator)); - users.bob.deleGator.redeemDelegation(encodedDelegations_, actions_); + users.bob.deleGator.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); } // should not allow to enable already enabled delegation @@ -362,19 +371,22 @@ abstract contract DeleGatorTestSuite is BaseTest { // Alice signs delegation delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get intermediate count uint256 intermediateValue_ = aliceDeleGatorCounter.count(); @@ -389,8 +401,9 @@ abstract contract DeleGatorTestSuite is BaseTest { ) ); - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory userOpCallData_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); uint256[] memory signers_ = new uint256[](1); signers_[0] = users.bob.privateKey; @@ -459,34 +472,6 @@ abstract contract DeleGatorTestSuite is BaseTest { assertFalse(isDisabled_); } - // should emit an event when the action_ is executed - function test_emit_executedActionEvent() public { - uint256 initialValue_ = aliceDeleGatorCounter.count(); - - // Bob's Delegator redeems the delegation - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - - // Creating a valid action - vm.prank(address(entryPoint)); - vm.expectEmit(true, true, true, true, address(users.alice.deleGator)); - emit ExecutedAction(action_.to, action_.value, true, hex""); - users.alice.deleGator.execute(action_); - - // Validate that the count has increased by 1 - uint256 updatedValue_ = aliceDeleGatorCounter.count(); - assertEq(updatedValue_, initialValue_ + 1); - - // Creating a invalid action_ - action_.value = 1; - vm.prank(address(entryPoint)); - // Expect it to emit a reverted event - vm.expectEmit(true, true, true, true, address(users.alice.deleGator)); - vm.expectRevert(abi.encodeWithSelector(ExecutionLib.FailedExecutionWithoutReason.selector)); - emit ExecutedAction(action_.to, action_.value, false, hex""); - users.alice.deleGator.execute(action_); - } - // should emit an event when paying the prefund function test_emit_sentPrefund() public { PackedUserOperation memory packedUserOperation_; @@ -527,12 +512,15 @@ abstract contract DeleGatorTestSuite is BaseTest { delegation_ = signDelegation(users.alice, delegation_); // Bob's Delegator redeems the delegation - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has increased by 1 updatedValue_ = aliceDeleGatorCounter.count(); @@ -542,13 +530,13 @@ abstract contract DeleGatorTestSuite is BaseTest { // Bob redeems the delegation vm.prank(users.bob.addr); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Validate that the count has increased by 1 updatedValue_ = aliceDeleGatorCounter.count(); @@ -591,21 +579,24 @@ abstract contract DeleGatorTestSuite is BaseTest { bobDelegation_ = signDelegation(users.bob, bobDelegation_); // Carol redeems the delegation - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = bobDelegation_; delegations_[1] = aliceDelegation_; // Carol redeems the delegation vm.prank(users.carol.addr); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Validate that the count has increased by 1 updatedValue_ = aliceDeleGatorCounter.count(); @@ -629,19 +620,22 @@ abstract contract DeleGatorTestSuite is BaseTest { delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); vm.prank(users.bob.addr); vm.expectRevert(); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode("quack"); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode("quack"); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; - delegationManager.redeemDelegation(encodedDelegations_, actions_); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -712,15 +706,18 @@ abstract contract DeleGatorTestSuite is BaseTest { // Alice signs delegation delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -747,9 +744,12 @@ abstract contract DeleGatorTestSuite is BaseTest { // Alice signs delegation delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Redeem Bob's delegation Delegation[] memory delegations_ = new Delegation[](1); @@ -757,13 +757,13 @@ abstract contract DeleGatorTestSuite is BaseTest { vm.prank(users.bob.addr); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -803,9 +803,12 @@ abstract contract DeleGatorTestSuite is BaseTest { bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(domainHash_, delegationHash2_); delegation2_.signature = SigningUtilsLib.signHash_EOA(users.bob.privateKey, typedDataHash_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Redeem Carol's delegation Delegation[] memory delegations_ = new Delegation[](2); @@ -814,13 +817,13 @@ abstract contract DeleGatorTestSuite is BaseTest { vm.prank(users.carol.addr); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -860,9 +863,12 @@ abstract contract DeleGatorTestSuite is BaseTest { bytes32 typedDataHash_ = MessageHashUtils.toTypedDataHash(domainHash_, delegationHash2_); delegation2_.signature = SigningUtilsLib.signHash_EOA(users.dave.privateKey, typedDataHash_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Redeem Carol's delegation Delegation[] memory delegations_ = new Delegation[](2); @@ -872,13 +878,13 @@ abstract contract DeleGatorTestSuite is BaseTest { vm.prank(users.carol.addr); vm.expectRevert(abi.encodeWithSelector(IDelegationManager.InvalidSignature.selector)); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Get final count // Validate that the count has increased by 1 @@ -914,15 +920,18 @@ abstract contract DeleGatorTestSuite is BaseTest { // Alice signs delegation delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Bob's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -962,16 +971,19 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign Bob's delegation bobDelegation_ = signDelegation(users.bob, bobDelegation_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Carol's UserOp Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = bobDelegation_; delegations_[1] = aliceDelegation_; - invokeDelegation_UserOp(users.carol, delegations_, action_); + invokeDelegation_UserOp(users.carol, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1011,23 +1023,28 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign Carol's delegation carolDelegation_ = signDelegation(users.carol, carolDelegation_); - // Create Dave's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + // Create Dave's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Execute Dave's UserOp Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = carolDelegation_; delegations_[1] = aliceDelegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); PackedUserOperation memory userOp_ = createAndSignUserOp( users.dave, address(users.dave.deleGator), - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_) + abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ) ); PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); @@ -1082,16 +1099,19 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign Bob's delegation bobDelegation_ = signDelegation(users.bob, bobDelegation_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Carol's UserOp Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = bobDelegation_; delegations_[1] = aliceDelegation_; - invokeDelegation_UserOp(users.carol, delegations_, action_); + invokeDelegation_UserOp(users.carol, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1131,9 +1151,12 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign Bob's delegation bobDelegation_ = signDelegation(users.bob, bobDelegation_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Carol's UserOp Delegation[] memory delegations_ = new Delegation[](2); @@ -1142,13 +1165,13 @@ abstract contract DeleGatorTestSuite is BaseTest { vm.prank(users.carol.addr); - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1157,20 +1180,26 @@ abstract contract DeleGatorTestSuite is BaseTest { assertEq(finalValue_, initialValue_ + 1); } - // should allow Alice to execute multiple actions_ in a single UserOp - function test_allow_multiAction_UserOp() public { + // should allow Alice to execute multiple executionCallDatas_ in a single UserOp + function test_allow_multiExecution_UserOp() public { // Get Alice's DeleGator's Counter's initial count uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create actions_ - Action[] memory actions_ = new Action[](2); - actions_[0] = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - actions_[1] = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create executionCallDatas_ + Execution[] memory executionCallDatas_ = new Execution[](2); + executionCallDatas_[0] = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + executionCallDatas_[1] = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); - // Execute Actions - executeBatch_UserOp(users.alice, actions_); + // Execute Executions + executeBatch_UserOp(users.alice, executionCallDatas_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1179,29 +1208,8 @@ abstract contract DeleGatorTestSuite is BaseTest { assertEq(finalValue_, initialValue_ + 2); } - // should not allow to execute empty Actions - function test_notAllow_emptyAction_UserOp() public { - //Create Actions - Action[] memory actions_ = new Action[](0); - - bytes memory userOpCallData__ = abi.encodeWithSelector(IDeleGatorCoreFull.executeBatch.selector, actions_); - PackedUserOperation memory userOp_ = createUserOp(address(users.alice.deleGator), userOpCallData__); - bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); - userOp_.signature = signHash(users.alice, userOpHash_.toEthSignedMessageHash()); - - PackedUserOperation[] memory userOps_ = new PackedUserOperation[](1); - userOps_[0] = userOp_; - vm.prank(bundler); - - vm.expectEmit(true, true, false, true, address(entryPoint)); - emit UserOperationRevertReason( - userOpHash_, address(users.alice.deleGator), 0, abi.encodeWithSelector(ExecutionLib.InvalidActionsLength.selector) - ); - entryPoint.handleOps(userOps_, payable(bundler)); - } - - // should allow Bob to execute multiple actions_ that redeem delegations_ in a single UserOp (offchain) - function test_allow_multiActionDelegationClaim_Offchain_UserOp() public { + // should allow Bob to execute multiple executionCallDatas_ that redeem delegations_ in a single UserOp (offchain) + function test_allow_multiExecutionDelegationClaim_Offchain_UserOp() public { // Get Alice's DeleGator's Counter's initial count uint256 initialValue_ = aliceDeleGatorCounter.count(); @@ -1218,28 +1226,34 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign delegation delegation_ = signDelegation(users.alice, delegation_); - // Create Action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + // Create Execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Invoke delegation calldata Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - bytes memory invokeDelegationCalldata_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory invokeDelegationCalldata_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); - // Create invoke delegation Actions - Action[] memory redemptionActions_ = new Action[](2); - redemptionActions_[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata_ }); - redemptionActions_[1] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata_ }); + // Create invoke delegation Executions + Execution[] memory redemptionExecutions_ = new Execution[](2); + redemptionExecutions_[0] = + Execution({ target: address(users.bob.deleGator), value: 0, callData: invokeDelegationCalldata_ }); + redemptionExecutions_[1] = + Execution({ target: address(users.bob.deleGator), value: 0, callData: invokeDelegationCalldata_ }); // Execute delegations_ - executeBatch_UserOp(users.bob, redemptionActions_); + executeBatch_UserOp(users.bob, redemptionExecutions_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1248,8 +1262,8 @@ abstract contract DeleGatorTestSuite is BaseTest { assertEq(finalValue_, initialValue_ + 2); } - // should allow Alice to execute a combination of actions_ through a single UserOp - function test_allow_multiActionCombination_UserOp() public { + // should allow Alice to execute a combination of executionCallDatas_ through a single UserOp + function test_allow_multiExecutionCombination_UserOp() public { // Get DeleGator's Counter's initial count uint256 initialValueAlice_ = aliceDeleGatorCounter.count(); uint256 initialValueBob_ = bobDeleGatorCounter.count(); @@ -1270,24 +1284,29 @@ abstract contract DeleGatorTestSuite is BaseTest { // Invoke delegation calldata Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = + ExecutionLib.encodeSingle(address(aliceDeleGatorCounter), 0, abi.encodeWithSelector(Counter.increment.selector)); - bytes memory invokeDelegationCalldata_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory invokeDelegationCalldata_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); - // Create invoke delegation Actions - Action[] memory redemptionActions_ = new Action[](2); - redemptionActions_[0] = Action({ to: address(users.bob.deleGator), value: 0, data: invokeDelegationCalldata_ }); - redemptionActions_[1] = - Action({ to: address(bobDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create invoke delegation Executions + Execution[] memory redemptionExecutions_ = new Execution[](2); + redemptionExecutions_[0] = + Execution({ target: address(users.bob.deleGator), value: 0, callData: invokeDelegationCalldata_ }); + redemptionExecutions_[1] = Execution({ + target: address(bobDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute delegations_ - executeBatch_UserOp(users.bob, redemptionActions_); + executeBatch_UserOp(users.bob, redemptionExecutions_); // Get final count uint256 finalValueAlice_ = aliceDeleGatorCounter.count(); @@ -1300,21 +1319,27 @@ abstract contract DeleGatorTestSuite is BaseTest { ////////////////////////////// Invalid cases ////////////////////////////// - // should not allow a second Action to execute if the first Action fails - function test_notAllow_multiActionUserOp() public { + // should not allow a second Execution to execute if the first Execution fails + function test_notAllow_multiExecutionUserOp() public { // Get Alice's DeleGator's Counter's initial count uint256 initialValueAlice_ = aliceDeleGatorCounter.count(); uint256 initialValueBob_ = bobDeleGatorCounter.count(); - // Create actions_, incorrectly incrementing Bob's Counter first - Action[] memory actions_ = new Action[](2); - actions_[0] = - Action({ to: address(bobDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - actions_[1] = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create executionCallDatas_, incorrectly incrementing Bob's Counter first + Execution[] memory executionCallDatas_ = new Execution[](2); + executionCallDatas_[0] = Execution({ + target: address(bobDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + executionCallDatas_[1] = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); - // Execute actions_ - executeBatch_UserOp(users.alice, actions_); + // Execute executionCallDatas_ + executeBatch_UserOp(users.alice, executionCallDatas_); // Get final count uint256 finalValueAlice_ = aliceDeleGatorCounter.count(); @@ -1327,14 +1352,15 @@ abstract contract DeleGatorTestSuite is BaseTest { // should revert without reason and catch it function test_executionRevertsWithoutReason() public { - // Invalid action_, sending ETH to a contract that can't receive it. - Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 1, data: hex"" }); + // Invalid execution_, sending ETH to a contract that can't receive it. + Execution memory execution_ = Execution({ target: address(aliceDeleGatorCounter), value: 1, callData: hex"" }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + ModeCode mode_ = ModeLib.encodeSimpleSingle(); vm.prank(address(delegationManager)); - - vm.expectRevert(abi.encodeWithSelector(ExecutionLib.FailedExecutionWithoutReason.selector)); - - users.alice.deleGator.executeDelegatedAction(action_); + // Expect it to emit a bubbled up reverted event + vm.expectRevert(); + users.alice.deleGator.executeFromExecutor(mode_, executionCallData_); } // should NOT allow Carol to redeem a delegation to Bob through a UserOp (offchain) @@ -1355,15 +1381,18 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign Alice's delegation to Bob delegation_ = signDelegation(users.alice, delegation_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Carol's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.carol, delegations_, action_); + invokeDelegation_UserOp(users.carol, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1402,7 +1431,7 @@ abstract contract DeleGatorTestSuite is BaseTest { IEntryPoint.FailedOpWithRevert.selector, 0, "AA23 reverted", - abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPoint.selector) + abi.encodeWithSelector(DeleGatorCore.NotEntryPoint.selector) ) ); newEntryPoint_.handleOps(userOps_, bundler); @@ -1419,7 +1448,7 @@ abstract contract DeleGatorTestSuite is BaseTest { IEntryPoint.FailedOpWithRevert.selector, 0, "AA23 reverted", - abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPoint.selector) + abi.encodeWithSelector(DeleGatorCore.NotEntryPoint.selector) ) ); newEntryPoint_.handleOps(userOps_, bundler); @@ -1427,12 +1456,15 @@ abstract contract DeleGatorTestSuite is BaseTest { // should NOT allow a UserOp with an invalid signature function test_notAllow_invalidUserOpSignature() public { - // Create action_ - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create execution_ + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Create Alice's UserOp - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_); + bytes memory userOpCallData_ = abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_); PackedUserOperation memory userOp_ = createUserOp(address(users.alice.deleGator), userOpCallData_, hex""); // Bob signs UserOp @@ -1447,13 +1479,16 @@ abstract contract DeleGatorTestSuite is BaseTest { // should NOT allow a UserOp with a reused nonce function test_notAllow_nonceReuse() public { - // Create action_ - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create execution_ + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Create and Sign Alice's UserOp PackedUserOperation memory userOp_ = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) + users.alice, address(users.alice.deleGator), abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_) ); // Submit the UserOp through the Bundler @@ -1467,14 +1502,14 @@ abstract contract DeleGatorTestSuite is BaseTest { ////////////////////////////// EVENTS Emission ////////////////////////////// function test_event_Deposited() public { - Action memory action_ = Action({ - to: address(users.alice.deleGator), + Execution memory execution_ = Execution({ + target: address(users.alice.deleGator), value: 1 ether, - data: abi.encodeWithSelector(IDeleGatorCoreFull.addDeposit.selector) + callData: abi.encodeWithSelector(DeleGatorCore.addDeposit.selector) }); PackedUserOperation memory userOp_ = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) + users.alice, address(users.alice.deleGator), abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_) ); vm.expectEmit(true, false, false, true); @@ -1484,26 +1519,26 @@ abstract contract DeleGatorTestSuite is BaseTest { } function test_allow_withdrawDeposit() public { - Action memory action_ = Action({ - to: address(users.alice.deleGator), + Execution memory execution_ = Execution({ + target: address(users.alice.deleGator), value: 1 ether, - data: abi.encodeWithSelector(IDeleGatorCoreFull.addDeposit.selector) + callData: abi.encodeWithSelector(DeleGatorCore.addDeposit.selector) }); PackedUserOperation memory userOp_ = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) + users.alice, address(users.alice.deleGator), abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_) ); submitUserOp_Bundler(userOp_); - action_ = Action({ - to: address(users.alice.deleGator), + execution_ = Execution({ + target: address(users.alice.deleGator), value: 0 ether, - data: abi.encodeWithSelector(IDeleGatorCoreFull.withdrawDeposit.selector, address(users.alice.addr), 0.5 ether) + callData: abi.encodeWithSelector(DeleGatorCore.withdrawDeposit.selector, address(users.alice.addr), 0.5 ether) }); userOp_ = createAndSignUserOp( - users.alice, address(users.alice.deleGator), abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_) + users.alice, address(users.alice.deleGator), abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_) ); vm.expectEmit(true, false, false, true); @@ -1563,23 +1598,26 @@ abstract contract DeleGatorTestSuite is BaseTest { // Store delegation delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Redeem Bob's delegation Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); vm.prank(users.bob.addr); vm.expectRevert(); - delegationManager.redeemDelegation(encodedDelegations_, actions_); + delegationManager.redeemDelegations(permissionContexts_, oneSingularMode, executionCallDatas_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); @@ -1602,20 +1640,24 @@ abstract contract DeleGatorTestSuite is BaseTest { delegation_ = signDelegation(users.alice, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); // create user operation calldata for invokeDelegation - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory userOpCallData_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); PackedUserOperation memory userOp_ = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData_); @@ -1652,11 +1694,14 @@ abstract contract DeleGatorTestSuite is BaseTest { // Sign Alice's delegation with Carol's private key delegation_ = signDelegation(users.carol, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // signing the userOp_ from bob uint256[] memory signers_ = new uint256[](1); @@ -1664,11 +1709,12 @@ abstract contract DeleGatorTestSuite is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory userOpCallData_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); @@ -1705,20 +1751,24 @@ abstract contract DeleGatorTestSuite is BaseTest { // Carol signs the delegation using Alice's domain hash delegation_ = signDelegation(users.carol, delegation_); - // Create Bob's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + // Create Bob's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); // create user operation calldata for invokeDelegation - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory userOpCallData_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); // create and sign user operation with Bob PackedUserOperation memory userOp_ = createAndSignUserOp(users.bob, address(users.bob.deleGator), userOpCallData_); @@ -1739,20 +1789,29 @@ abstract contract DeleGatorTestSuite is BaseTest { entryPoint.handleOps(userOps_, bundler); } - // Should revert if executeDelegatedAction is called from an address other than the DelegationManager + // Should revert if executeFromExecutor is called from an address other than the DelegationManager function test_notAllow_notDelegationManager() public { - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotDelegationManager.selector)); - users.alice.deleGator.executeDelegatedAction(action_); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + ModeCode mode_ = ModeLib.encodeSimpleSingle(); + + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotDelegationManager.selector)); + users.alice.deleGator.executeFromExecutor(mode_, executionCallData_); } // Should revert if execute is called from an address other than the EntryPoint function test_notAllow_notEntryPoint() public { - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPoint.selector)); - users.alice.deleGator.execute(action_); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPoint.selector)); + users.alice.deleGator.execute(execution_); } // Should revert if the delegation chain contains invalid authority @@ -1792,22 +1851,26 @@ abstract contract DeleGatorTestSuite is BaseTest { bobDelegation_ = signDelegation(users.bob, bobDelegation_); - // Create Carol's action - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Carol's execution + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); Delegation[] memory delegations_ = new Delegation[](2); delegations_[0] = bobDelegation_; delegations_[1] = aliceDelegation_; - bytes[] memory encodedDelegations_ = new bytes[](1); - encodedDelegations_[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // create user operation calldata for invokeDelegation - bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, encodedDelegations_, actions_); + bytes memory userOpCallData_ = abi.encodeWithSelector( + DeleGatorCore.redeemDelegations.selector, permissionContexts_, oneSingularMode, executionCallDatas_ + ); PackedUserOperation memory userOp_ = createAndSignUserOp(users.carol, address(users.carol.deleGator), userOpCallData_); diff --git a/test/DelegationManagerTest.t.sol b/test/DelegationManagerTest.t.sol index 00a23f4..285d369 100644 --- a/test/DelegationManagerTest.t.sol +++ b/test/DelegationManagerTest.t.sol @@ -6,30 +6,47 @@ import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Ownable2Step } from "@openzeppelin/contracts/access/Ownable2Step.sol"; import { ShortStrings, ShortString } from "@openzeppelin/contracts/utils/ShortStrings.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import { Counter } from "./utils/Counter.t.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; -import { Delegation, Caveat, Action } from "../src/utils/Types.sol"; +import { Delegation, Caveat, Execution, ModeCode } from "../src/utils/Types.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; import { DelegationManager } from "../src/DelegationManager.sol"; import { Invalid1271Returns, Invalid1271Reverts } from "./utils/Invalid1271.t.sol"; import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; -import { EIP712_DOMAIN_TYPEHASH } from "../src/utils/Typehashes.sol"; +import { EIP712_DOMAIN_TYPEHASH } from "../src/utils/Constants.sol"; import { MockCaveatEnforcer } from "./utils/MockCaveatEnforcer.sol"; import { MockFailureCaveatEnforcer } from "./utils/MockFailureCaveatEnforcer.sol"; contract DelegationManagerTest is BaseTest { + using ModeLib for ModeCode; using ShortStrings for *; + ////////////////////////////// Setup ////////////////////////////// string private _nameFallback; string private _versionFallback; + ModeCode[] _oneSingularMode; + ModeCode[] _twoSingularModes; constructor() { IMPLEMENTATION = Implementation.Hybrid; SIGNATURE_TYPE = SignatureType.RawP256; } + function setUp() public virtual override { + super.setUp(); + + _oneSingularMode = new ModeCode[](1); + _oneSingularMode[0] = ModeLib.encodeSimpleSingle(); + + _twoSingularModes = new ModeCode[](2); + _twoSingularModes[0] = ModeLib.encodeSimpleSingle(); + _twoSingularModes[1] = ModeLib.encodeSimpleSingle(); + } + ////////////////////////////// Events ////////////////////////////// event SetDomain( @@ -50,7 +67,7 @@ contract DelegationManagerTest is BaseTest { // Should allow reading contract version function test_allow_contractVersionReads() public { string memory contractVersion_ = delegationManager.VERSION(); - assertEq("1.0.0", contractVersion_); + assertEq("1.1.0", contractVersion_); } // Should allow reading contract version @@ -164,13 +181,13 @@ contract DelegationManagerTest is BaseTest { vm.prank(address(users.bob.addr)); - bytes[] memory dataArray = new bytes[](1); - dataArray[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = Action({ to: address(0), data: new bytes(0), value: 0 }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = abi.encode(Execution({ target: address(0), callData: new bytes(0), value: 0 })); - delegationManager.redeemDelegation(dataArray, actions_); + delegationManager.redeemDelegations(permissionContexts_, _oneSingularMode, executionCallDatas_); } function test_notAllow_invalidSignatureReturns() public { @@ -192,13 +209,13 @@ contract DelegationManagerTest is BaseTest { vm.prank(address(users.bob.addr)); - bytes[] memory dataArray = new bytes[](1); - dataArray[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); - Action[] memory actions_ = new Action[](1); - actions_[0] = Action({ to: address(0), data: new bytes(0), value: 0 }); + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = abi.encode(Execution({ target: address(0), callData: new bytes(0), value: 0 })); - delegationManager.redeemDelegation(dataArray, actions_); + delegationManager.redeemDelegations(permissionContexts_, _oneSingularMode, executionCallDatas_); } function test_allow_redeemBatchDelegation() public { @@ -226,7 +243,7 @@ contract DelegationManagerTest is BaseTest { }); delegation2.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); - bytes[] memory permissionContexts = new bytes[](2); + bytes[] memory permissionContexts_ = new bytes[](2); // Sign delegations delegation1 = signDelegation(users.alice, delegation1); @@ -234,97 +251,26 @@ contract DelegationManagerTest is BaseTest { Delegation[] memory delegations1 = new Delegation[](1); delegations1[0] = delegation1; - permissionContexts[0] = abi.encode(delegations1); + permissionContexts_[0] = abi.encode(delegations1); Delegation[] memory delegations2 = new Delegation[](1); delegations2[0] = delegation2; - permissionContexts[1] = abi.encode(delegations2); + permissionContexts_[1] = abi.encode(delegations2); - Action[] memory actions = new Action[](2); - actions[0] = Action({ to: address(0), data: hex"", value: 0 }); - actions[1] = Action({ to: address(0), data: hex"", value: 0 }); + bytes[] memory executionCallDatas_ = new bytes[](2); + executionCallDatas_[0] = ExecutionLib.encodeSingle(address(0), 0, hex""); + executionCallDatas_[1] = ExecutionLib.encodeSingle(address(0), 0, hex""); vm.prank(address(users.bob.addr)); - delegationManager.redeemDelegation(permissionContexts, actions); + delegationManager.redeemDelegations(permissionContexts_, _twoSingularModes, executionCallDatas_); - // Assert that beforeHook was called for each action + // Assert that beforeHook was called for each execution assertEq(mockEnforcer.beforeHookCallCount(), 2); - // Assert that afterHook was called after executing all actions + // Assert that afterHook was called after executing all executions assertEq(mockEnforcer.afterHookCallCount(), 2); } - function test_allow_redeemBatchDelegationMixedWithNoDelegation() public { - Counter aliceDeleGatorCounter = new Counter(address(users.alice.deleGator)); - Counter bobDeleGatorCounter = new Counter(address(users.bob.deleGator)); - - // Create a mock caveat enforcers contract - MockCaveatEnforcer mockEnforcer = new MockCaveatEnforcer(); - - // Create delegations with caveats - Delegation memory delegation1 = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](1), - salt: 0, - signature: hex"" - }); - delegation1.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); - - // Create delegations with caveats - Delegation memory delegation3 = Delegation({ - delegate: address(users.bob.deleGator), - delegator: address(users.alice.deleGator), - authority: ROOT_AUTHORITY, - caveats: new Caveat[](1), - salt: 0, - signature: hex"" - }); - delegation3.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); - - bytes[] memory permissionContexts = new bytes[](3); - - // Sign delegations - delegation1 = signDelegation(users.alice, delegation1); - delegation3 = signDelegation(users.alice, delegation3); - - Delegation[] memory delegations1 = new Delegation[](1); - delegations1[0] = delegation1; - permissionContexts[0] = abi.encode(delegations1); - - // This is an empty delegation for a self execution - Delegation[] memory delegations2 = new Delegation[](0); - permissionContexts[1] = abi.encode(delegations2); - - Delegation[] memory delegations3 = new Delegation[](1); - delegations3[0] = delegation3; - permissionContexts[2] = abi.encode(delegations3); - - Action memory incrementCounter_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - Action[] memory actions = new Action[](3); - actions[0] = incrementCounter_; - actions[1] = - Action({ to: address(bobDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - actions[2] = incrementCounter_; - - assertEq(aliceDeleGatorCounter.count(), 0); - assertEq(bobDeleGatorCounter.count(), 0); - - vm.prank(address(users.bob.deleGator)); - delegationManager.redeemDelegation(permissionContexts, actions); - - // Assert that beforeHook was called for each action - assertEq(mockEnforcer.beforeHookCallCount(), 2); - - // Assert that afterHook was called after executing all actions - assertEq(mockEnforcer.afterHookCallCount(), 2); - - assertEq(aliceDeleGatorCounter.count(), 2); - assertEq(bobDeleGatorCounter.count(), 1); - } - function test_allow_redeemBatchWithEoaInSecondBatchDelegation() public { // Create a mock caveat enforcers contract MockCaveatEnforcer mockEnforcer = new MockCaveatEnforcer(); @@ -362,7 +308,7 @@ contract DelegationManagerTest is BaseTest { }); delegation3.caveats[0] = Caveat({ enforcer: address(mockEnforcer), terms: hex"", args: hex"" }); - bytes[] memory permissionContexts = new bytes[](2); + bytes[] memory permissionContexts_ = new bytes[](2); // Sign delegations delegation1 = signDelegation(users.alice, delegation1); @@ -376,24 +322,24 @@ contract DelegationManagerTest is BaseTest { Delegation[] memory delegations1 = new Delegation[](1); delegations1[0] = delegation1; - permissionContexts[0] = abi.encode(delegations1); + permissionContexts_[0] = abi.encode(delegations1); Delegation[] memory delegations2 = new Delegation[](2); delegations2[0] = delegation3; delegations2[1] = delegation2; - permissionContexts[1] = abi.encode(delegations2); + permissionContexts_[1] = abi.encode(delegations2); - Action[] memory actions = new Action[](2); - actions[0] = Action({ to: address(0), data: hex"", value: 0 }); - actions[1] = Action({ to: address(0), data: hex"", value: 0 }); + bytes[] memory executionCallDatas_ = new bytes[](2); + executionCallDatas_[0] = ExecutionLib.encodeSingle(address(0), 0, hex""); + executionCallDatas_[1] = ExecutionLib.encodeSingle(address(0), 0, hex""); vm.prank(address(users.carol.addr)); - delegationManager.redeemDelegation(permissionContexts, actions); + delegationManager.redeemDelegations(permissionContexts_, _twoSingularModes, executionCallDatas_); - // Assert that beforeHook was called for each action + // Assert that beforeHook was called for each execution assertEq(mockEnforcer.beforeHookCallCount(), 3); - // Assert that afterHook was called after executing all actions + // Assert that afterHook was called after executing all executions assertEq(mockEnforcer.afterHookCallCount(), 3); } @@ -424,7 +370,7 @@ contract DelegationManagerTest is BaseTest { }); delegation2.caveats[0] = Caveat({ enforcer: address(mockFailureEnforcer), terms: hex"", args: hex"" }); - bytes[] memory permissionContexts = new bytes[](2); + bytes[] memory permissionContexts_ = new bytes[](2); // Sign delegations delegation1 = signDelegation(users.alice, delegation1); @@ -432,19 +378,19 @@ contract DelegationManagerTest is BaseTest { Delegation[] memory delegations1 = new Delegation[](1); delegations1[0] = delegation1; - permissionContexts[0] = abi.encode(delegations1); + permissionContexts_[0] = abi.encode(delegations1); Delegation[] memory delegations2 = new Delegation[](1); delegations2[0] = delegation2; - permissionContexts[1] = abi.encode(delegations2); + permissionContexts_[1] = abi.encode(delegations2); - Action[] memory actions_ = new Action[](2); - actions_[0] = Action({ to: address(0), data: hex"", value: 0 }); - actions_[1] = Action({ to: address(0), data: hex"", value: 0 }); + bytes[] memory executionCallDatas_ = new bytes[](2); + executionCallDatas_[0] = ExecutionLib.encodeSingle(address(0), 0, hex""); + executionCallDatas_[1] = ExecutionLib.encodeSingle(address(0), 0, hex""); vm.prank(address(users.bob.addr)); vm.expectRevert(); - delegationManager.redeemDelegation(permissionContexts, actions_); + delegationManager.redeemDelegations(permissionContexts_, _twoSingularModes, executionCallDatas_); } /////////////////////////////// Ownership ////////////////////////////// @@ -535,13 +481,11 @@ contract DelegationManagerTest is BaseTest { vm.startPrank(delegationManager.owner()); delegationManager.pause(); - Action[] memory actions_ = new Action[](1); - + bytes[] memory executionCallDatas_ = new bytes[](1); bytes[] memory permissionContexts_ = new bytes[](1); - permissionContexts_[0] = hex""; vm.expectRevert(Pausable.EnforcedPause.selector); - delegationManager.redeemDelegation(permissionContexts_, actions_); + delegationManager.redeemDelegations(permissionContexts_, _oneSingularMode, executionCallDatas_); } // Should fail to pause when the pause is active diff --git a/test/HybridDeleGatorTest.t.sol b/test/HybridDeleGatorTest.t.sol index a077971..f2bf097 100644 --- a/test/HybridDeleGatorTest.t.sol +++ b/test/HybridDeleGatorTest.t.sol @@ -6,18 +6,20 @@ import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy import { FCL_ecdsa_utils } from "@freshCryptoLib/FCL_ecdsa_utils.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { BytesLib } from "@bytes-utils/BytesLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; import { StorageUtilsLib } from "./utils/StorageUtilsLib.t.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; -import { Action, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; +import { Execution, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; import { HybridDeleGator } from "../src/HybridDeleGator.sol"; -import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; import { IDeleGatorCore } from "../src/interfaces/IDeleGatorCore.sol"; +import { DeleGatorCore } from "../src/DeleGatorCore.sol"; import { IERC173 } from "../src/interfaces/IERC173.sol"; import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; +import { EXECUTE_SINGULAR_SIGNATURE } from "./utils/Constants.sol"; contract HybridDeleGator_Test is BaseTest { using MessageHashUtils for bytes32; @@ -95,12 +97,12 @@ contract HybridDeleGator_Test is BaseTest { // Should emit AddedP256Key in addKey function test_keyAdded_addKey() public { // Create and Sign UserOp - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ - to: address(aliceDeleGator), + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(aliceDeleGator), value: 0, - data: abi.encodeWithSelector(HybridDeleGator.addKey.selector, keyId, users.alice.x, users.alice.y) + callData: abi.encodeWithSelector(HybridDeleGator.addKey.selector, keyId, users.alice.x, users.alice.y) }) ); PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(aliceDeleGator), userOpCallData_); @@ -117,9 +119,13 @@ contract HybridDeleGator_Test is BaseTest { execute_UserOp(users.alice, abi.encodeWithSelector(HybridDeleGator.addKey.selector, keyId, users.alice.x, users.alice.y)); // Create and Sign UserOp - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ to: address(aliceDeleGator), value: 0, data: abi.encodeWithSelector(HybridDeleGator.removeKey.selector, keyId) }) + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(aliceDeleGator), + value: 0, + callData: abi.encodeWithSelector(HybridDeleGator.removeKey.selector, keyId) + }) ); PackedUserOperation memory userOp_ = createAndSignUserOp(users.alice, address(aliceDeleGator), userOpCallData_); @@ -328,7 +334,7 @@ contract HybridDeleGator_Test is BaseTest { // Replace the signers vm.startPrank(address(aliceDeleGator)); aliceDeleGator.reinitialize( - uint8(IDeleGatorCoreFull(address(aliceDeleGator)).getInitializedVersion() + 1), + uint8(DeleGatorCore(payable(address(aliceDeleGator))).getInitializedVersion() + 1), users.bob.addr, keyIds_, xValues_, @@ -363,7 +369,7 @@ contract HybridDeleGator_Test is BaseTest { // Replace the signers vm.startPrank(address(aliceDeleGator)); aliceDeleGator.reinitialize( - uint8(IDeleGatorCoreFull(address(aliceDeleGator)).getInitializedVersion() + 1), + uint8(DeleGatorCore(payable(address(aliceDeleGator))).getInitializedVersion() + 1), users.bob.addr, keyIds_, xValues_, @@ -402,11 +408,11 @@ contract HybridDeleGator_Test is BaseTest { execute_UserOp( users.alice, abi.encodeWithSelector( - IDeleGatorCoreFull.upgradeToAndCall.selector, + DeleGatorCore.upgradeToAndCall.selector, address(hybridDeleGatorImpl), abi.encodeWithSelector( HybridDeleGator.reinitialize.selector, - IDeleGatorCoreFull(deleGator_).getInitializedVersion() + 1, + DeleGatorCore(deleGator_).getInitializedVersion() + 1, users.bob.addr, keyIds_, xValues_, @@ -418,7 +424,7 @@ contract HybridDeleGator_Test is BaseTest { ); // Assert DeleGator is Hybrid - assertEq(address(IDeleGatorCoreFull(deleGator_).getImplementation()), address(hybridDeleGatorImpl)); + assertEq(address(DeleGatorCore(deleGator_).getImplementation()), address(hybridDeleGatorImpl)); // ERC4337 should be the same assertEq(delegatorCoreStoragePre_, vm.load(deleGator_, DELEGATOR_CORE_STORAGE_LOCATION)); @@ -491,7 +497,7 @@ contract HybridDeleGator_Test is BaseTest { function test_notAllow_transferOwnership_directOwner() public { // Submit Alice's tx vm.prank(users.alice.addr); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.transferOwnership(users.bob.addr); } @@ -499,7 +505,7 @@ contract HybridDeleGator_Test is BaseTest { function test_notAllow_transferOwnership_directNonOwner() public { // Submit Bob's tx vm.prank(users.bob.addr); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.transferOwnership(users.bob.addr); } @@ -525,12 +531,12 @@ contract HybridDeleGator_Test is BaseTest { assertEq(users.alice.addr, onlyEoaHybridDeleGator.owner()); // Create and Sign UserOp - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ - to: address(onlyEoaHybridDeleGator), + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(onlyEoaHybridDeleGator), value: 0, - data: abi.encodeWithSelector( + callData: abi.encodeWithSelector( HybridDeleGator.updateSigners.selector, users.bob.addr, new string[](0), new uint256[](0), new uint256[](0) ) }) @@ -560,12 +566,12 @@ contract HybridDeleGator_Test is BaseTest { yValues_[0] = users.bob.y; // Create and Sign UserOp - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ - to: address(onlyEoaHybridDeleGator), + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(onlyEoaHybridDeleGator), value: 0, - data: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, address(0), keyIds_, xValues_, yValues_) + callData: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, address(0), keyIds_, xValues_, yValues_) }) ); PackedUserOperation memory userOp_ = createUserOp(address(onlyEoaHybridDeleGator), userOpCallData_); @@ -595,12 +601,12 @@ contract HybridDeleGator_Test is BaseTest { yValues_[0] = users.bob.y; // Create and Sign UserOp - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ - to: address(onlyEoaHybridDeleGator), + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(onlyEoaHybridDeleGator), value: 0, - data: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, users.bob.addr, keyIds_, xValues_, yValues_) + callData: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, users.bob.addr, keyIds_, xValues_, yValues_) }) ); PackedUserOperation memory userOp_ = createUserOp(address(onlyEoaHybridDeleGator), userOpCallData_); @@ -632,11 +638,11 @@ contract HybridDeleGator_Test is BaseTest { xValues_[0] = users.bob.x; yValues_[0] = users.bob.y; - // Create the action that would be executed - Action memory action_ = Action({ - to: address(aliceDeleGator), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGator), value: 0, - data: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, users.bob.addr, keyIds_, xValues_, yValues_) + callData: abi.encodeWithSelector(HybridDeleGator.updateSigners.selector, users.bob.addr, keyIds_, xValues_, yValues_) }); Caveat[] memory caveats_ = new Caveat[](0); @@ -656,7 +662,7 @@ contract HybridDeleGator_Test is BaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Bob is the EOA owner now (uint256 x__, uint256 y__) = aliceDeleGator.getKey(users.bob.name); @@ -685,13 +691,13 @@ contract HybridDeleGator_Test is BaseTest { vm.prank(address(entryPoint)); aliceDeleGator.addKey(webAuthnKeyId_, xWebAuthn_, yWebAuthn_); - // Create the action that would be executed - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ - to: address(aliceDeleGator), + // Create the execution that would be executed + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(aliceDeleGator), value: 0, - data: abi.encodeWithSelector(Ownable.transferOwnership.selector, address(1)) + callData: abi.encodeWithSelector(Ownable.transferOwnership.selector, address(1)) }) ); PackedUserOperation memory userOp_ = createUserOp(address(aliceDeleGator), userOpCallData_); @@ -745,13 +751,13 @@ contract HybridDeleGator_Test is BaseTest { vm.prank(address(entryPoint)); aliceDeleGator.addKey(webAuthnKeyId_, xWebAuthn_, yWebAuthn_); - // Create the action that would be executed - bytes memory userOpCallData_ = abi.encodeWithSelector( - IDeleGatorCoreFull.execute.selector, - Action({ - to: address(aliceDeleGator), + // Create the execution that would be executed + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SINGULAR_SIGNATURE, + Execution({ + target: address(aliceDeleGator), value: 0, - data: abi.encodeWithSelector(Ownable.transferOwnership.selector, address(1)) + callData: abi.encodeWithSelector(Ownable.transferOwnership.selector, address(1)) }) ); PackedUserOperation memory userOp_ = createUserOp(address(aliceDeleGator), userOpCallData_); diff --git a/test/InviteTest.t.sol b/test/InviteTest.t.sol index 0a64ec0..d833572 100644 --- a/test/InviteTest.t.sol +++ b/test/InviteTest.t.sol @@ -3,19 +3,23 @@ pragma solidity 0.8.23; import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; -import { Delegation, Action, PackedUserOperation, Caveat } from "../src/utils/Types.sol"; +import { Delegation, Execution, PackedUserOperation, Caveat, ModeCode } from "../src/utils/Types.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; import { Counter } from "./utils/Counter.t.sol"; import { MultiSigDeleGator } from "../src/MultiSigDeleGator.sol"; -import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; +import { DeleGatorCore } from "../src/DeleGatorCore.sol"; import { SimpleFactory } from "../src/utils/SimpleFactory.sol"; import { AllowedTargetsEnforcer } from "../src/enforcers/AllowedTargetsEnforcer.sol"; import { AllowedMethodsEnforcer } from "../src/enforcers/AllowedMethodsEnforcer.sol"; +import { EXECUTE_SINGULAR_SIGNATURE } from "./utils/Constants.sol"; contract InviteTest is BaseTest { using MessageHashUtils for bytes32; + using ModeLib for ModeCode; constructor() { IMPLEMENTATION = Implementation.Hybrid; @@ -63,22 +67,22 @@ contract InviteTest is BaseTest { abi.encodeWithSelector(SimpleFactory.deploy.selector, abi.encodePacked(type(ERC1967Proxy).creationCode, args_), salt) ); - // Create action to send ETH to Bob - Action memory action_ = Action({ to: address(users.bob.addr), value: 1, data: hex"" }); + // Create execution to send ETH to Bob + Execution memory execution_ = Execution({ target: address(users.bob.addr), value: 1, callData: hex"" }); - // Give the new MultiSigDeleGator some funds to pay for the action + // Give the new MultiSigDeleGator some funds to pay for the execution vm.deal(predictedAddr_, 100); // Preload the EntryPoint with funds for the new MultiSigDeleGator vm.prank(users.alice.addr); entryPoint.depositTo{ value: 5 ether }(predictedAddr_); - // Fetch balance before action executes + // Fetch balance before execution executes uint256 balanceBefore_ = users.bob.addr.balance; // Create and Sign UserOp with Bob's key PackedUserOperation memory userOp_ = createAndSignUserOp( - users.bob, predictedAddr_, abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_), initcode_ + users.bob, predictedAddr_, abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_), initcode_ ); // Validate the contract hasn't been deployed yet @@ -87,7 +91,7 @@ contract InviteTest is BaseTest { // Submit the UserOp through the Bundler submitUserOp_Bundler(userOp_); - // Fetch balance after action executes + // Fetch balance after execution executes uint256 balanceAfter_ = users.bob.addr.balance; assertEq(balanceAfter_, balanceBefore_ + 1); @@ -149,7 +153,7 @@ contract InviteTest is BaseTest { delegation_ = signDelegation(users.alice, delegation_); } - // Give the new MultiSigDeleGator some funds to pay for the action + // Give the new MultiSigDeleGator some funds to pay for the execution vm.deal(predictedAddr_, 100); // Preload the EntryPoint with funds for the new MultiSigDeleGator @@ -160,25 +164,29 @@ contract InviteTest is BaseTest { uint256[] memory counts_ = new uint256[](2); counts_[0] = aliceDeleGatorCounter.count(); - // Create action to deploy a new MultiSigDeleGator and execute Bob's UserOp - Action memory action_; - { - action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); - } + // Create execution to deploy a new MultiSigDeleGator and execute Bob's UserOp + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Bob's UserOp { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - bytes[] memory dataArray = new bytes[](1); - dataArray[0] = abi.encode(delegations_); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(delegations_); + + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); - Action[] memory actions_ = new Action[](1); - actions_[0] = action_; + ModeCode[] memory modes_ = new ModeCode[](1); + modes_[0] = ModeLib.encodeSimpleSingle(); - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, dataArray, actions_); + bytes memory userOpCallData_ = + abi.encodeWithSelector(DeleGatorCore.redeemDelegations.selector, permissionContexts_, modes_, executionCallDatas_); PackedUserOperation memory userOp_ = createUserOp(predictedAddr_, userOpCallData_, initcode_); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(users.bob, userOpHash_.toEthSignedMessageHash()); diff --git a/test/MultiSigDeleGatorTest.t.sol b/test/MultiSigDeleGatorTest.t.sol index 8351c51..a143935 100644 --- a/test/MultiSigDeleGatorTest.t.sol +++ b/test/MultiSigDeleGatorTest.t.sol @@ -10,12 +10,12 @@ import { ERC1967Proxy as DeleGatorProxy } from "@openzeppelin/contracts/proxy/ER import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; -import { Action, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; +import { Execution, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; import { AccountSorterLib } from "./utils/AccountSorterLib.t.sol"; import { MultiSigDeleGator } from "../src/MultiSigDeleGator.sol"; import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; -import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; +import { DeleGatorCore } from "../src/DeleGatorCore.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; import { Counter } from "./utils/Counter.t.sol"; import { SimpleFactory } from "../src/utils/SimpleFactory.sol"; @@ -126,7 +126,7 @@ contract MultiSigDeleGatorTest is BaseTest { abi.encodeWithSelector(SimpleFactory.deploy.selector, abi.encodePacked(type(DeleGatorProxy).creationCode, args_), salt) ); - // Give the new MultiSigDeleGator some funds to pay for the action + // Give the new MultiSigDeleGator some funds to pay for the execution vm.deal(predictedAddr_, 100); // Preload the EntryPoint with funds for the new MultiSigDeleGator @@ -167,15 +167,18 @@ contract MultiSigDeleGatorTest is BaseTest { bytes memory signature_ = SigningUtilsLib.signHash_MultiSig(sharedDeleGatorPrivateKeys, typedDataHash_); delegation_.signature = signature_; - // Create Dave's action - Action memory action_ = - Action({ to: address(sharedDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create Dave's execution + Execution memory execution_ = Execution({ + target: address(sharedDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); // Execute Dave's UserOp Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.dave, delegations_, action_); + invokeDelegation_UserOp(users.dave, delegations_, execution_); // Get final count uint256 finalValue_ = sharedDeleGatorCounter.count(); @@ -518,7 +521,7 @@ contract MultiSigDeleGatorTest is BaseTest { // Don't allow someone else to replace Alice's MultiSigDeleGator's signers // replaceSigner call must come from the MultiSigDeleGator itself vm.prank(address(users.alice.addr)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.replaceSigner(users.alice.addr, users.bob.addr); // Mock calls from the MultiSigDeleGator itself @@ -572,7 +575,7 @@ contract MultiSigDeleGatorTest is BaseTest { // Don't allow someone else to remove signers. // Call must come from the MultiSigDeleGator itself. vm.prank(address(users.alice.addr)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.addSigner(users.bob.addr); // Mock calls from the MultiSigDeleGator itself @@ -656,7 +659,7 @@ contract MultiSigDeleGatorTest is BaseTest { // Don't allow someone else to remove signers. // Call must come from the MultiSigDeleGator itself. vm.prank(address(users.alice.addr)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.removeSigner(users.alice.addr); // Mock calls from the MultiSigDeleGator itself @@ -700,7 +703,7 @@ contract MultiSigDeleGatorTest is BaseTest { // Don't allow someone else to remove signers. // Call must come from the MultiSigDeleGator itself. vm.prank(address(users.alice.addr)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.updateThreshold(1); uint256 preThreshold_ = aliceDeleGator.getThreshold(); @@ -729,17 +732,17 @@ contract MultiSigDeleGatorTest is BaseTest { // Don't allow Alice to update Alice's MultiSigDeleGator's signers vm.prank(address(users.alice.addr)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.updateMultiSigParameters(signers_, 1, false); // Don't allow Bob to update Alice's MultiSigDeleGator's signers vm.prank(address(users.bob.addr)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.updateMultiSigParameters(signers_, 1, false); // Don't allow Bob's MultiSigDeleGator to update Alice's MultiSigDeleGator's signers vm.prank(address(bobDeleGator)); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); aliceDeleGator.updateMultiSigParameters(signers_, 1, false); } @@ -851,12 +854,12 @@ contract MultiSigDeleGatorTest is BaseTest { // Load DeleGator to manipulate address payable delegator_ = payable(address(aliceDeleGator)); - uint64 version_ = IDeleGatorCoreFull(delegator_).getInitializedVersion() + 1; + uint64 version_ = DeleGatorCore(delegator_).getInitializedVersion() + 1; address[] memory newSigners_ = new address[](1); newSigners_[0] = users.bob.addr; vm.prank(users.bob.addr); - vm.expectRevert(abi.encodeWithSelector(IDeleGatorCoreFull.NotEntryPointOrSelf.selector)); + vm.expectRevert(abi.encodeWithSelector(DeleGatorCore.NotEntryPointOrSelf.selector)); MultiSigDeleGator(delegator_).reinitialize(version_, newSigners_, 1, false); } diff --git a/test/ProxyMigrationTest.t.sol b/test/ProxyMigrationTest.t.sol index 2baaee1..9406fe7 100644 --- a/test/ProxyMigrationTest.t.sol +++ b/test/ProxyMigrationTest.t.sol @@ -10,13 +10,14 @@ import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/Mes import { SigningUtilsLib } from "./utils/SigningUtilsLib.t.sol"; import { StorageUtilsLib } from "./utils/StorageUtilsLib.t.sol"; import { Implementation, SignatureType } from "./utils/Types.t.sol"; -import { Action, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; +import { Execution, PackedUserOperation, Caveat, Delegation } from "../src/utils/Types.sol"; import { BaseTest } from "./utils/BaseTest.t.sol"; import { HybridDeleGator } from "../src/HybridDeleGator.sol"; import { MultiSigDeleGator } from "../src/MultiSigDeleGator.sol"; -import { IDeleGatorCoreFull } from "../src/interfaces/IDeleGatorCoreFull.sol"; +import { DeleGatorCore } from "../src/DeleGatorCore.sol"; import { IDelegationManager } from "../src/interfaces/IDelegationManager.sol"; import { EncoderLib } from "../src/libraries/EncoderLib.sol"; +import { EXECUTE_SINGULAR_SIGNATURE } from "./utils/Constants.sol"; contract HybridDeleGator_Test is BaseTest { using MessageHashUtils for bytes32; @@ -43,18 +44,18 @@ contract HybridDeleGator_Test is BaseTest { vm.deal(deleGator_, 100 ether); // Assert DeleGator is MultiSig - assertEq(address(IDeleGatorCoreFull(deleGator_).getImplementation()), address(multiSigDeleGatorImpl)); + assertEq(address(DeleGatorCore(deleGator_).getImplementation()), address(multiSigDeleGatorImpl)); // Upgrade to Hybrid - Action memory action_ = Action({ - to: address(deleGator_), + Execution memory execution_ = Execution({ + target: address(deleGator_), value: 0, - data: abi.encodeWithSelector( - IDeleGatorCoreFull.upgradeToAndCall.selector, + callData: abi.encodeWithSelector( + DeleGatorCore.upgradeToAndCall.selector, address(hybridDeleGatorImpl), abi.encodeWithSelector( HybridDeleGator.reinitialize.selector, - IDeleGatorCoreFull(deleGator_).getInitializedVersion() + 1, + DeleGatorCore(deleGator_).getInitializedVersion() + 1, users.alice.addr, new string[](0), new uint256[](0), @@ -63,7 +64,7 @@ contract HybridDeleGator_Test is BaseTest { ) ) }); - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_); + bytes memory userOpCallData_ = abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_); PackedUserOperation memory userOp_ = createUserOp(address(deleGator_), userOpCallData_); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(SignatureType.MultiSig, users.alice, userOpHash_.toEthSignedMessageHash()); @@ -74,7 +75,7 @@ contract HybridDeleGator_Test is BaseTest { submitUserOp_Bundler(userOp_); // Assert DeleGator is Hybrid - assertEq(address(IDeleGatorCoreFull(deleGator_).getImplementation()), address(hybridDeleGatorImpl)); + assertEq(address(DeleGatorCore(deleGator_).getImplementation()), address(hybridDeleGatorImpl)); // Assert MultiSig storage was cleared bytes32 DEFAULT_MULTISIG_DELEGATOR_STORAGE_LOCATION = StorageUtilsLib.getStorageLocation("DeleGator.MultiSigDeleGator"); @@ -95,22 +96,18 @@ contract HybridDeleGator_Test is BaseTest { // Upgrade to MultiSig owners_ = new address[](1); owners_[0] = users.alice.addr; - action_ = Action({ - to: address(deleGator_), + execution_ = Execution({ + target: address(deleGator_), value: 0, - data: abi.encodeWithSelector( - IDeleGatorCoreFull.upgradeToAndCall.selector, + callData: abi.encodeWithSelector( + DeleGatorCore.upgradeToAndCall.selector, address(multiSigDeleGatorImpl), abi.encodeWithSelector( - MultiSigDeleGator.reinitialize.selector, - IDeleGatorCoreFull(deleGator_).getInitializedVersion() + 1, - owners_, - 1, - false + MultiSigDeleGator.reinitialize.selector, DeleGatorCore(deleGator_).getInitializedVersion() + 1, owners_, 1, false ) ) }); - userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_); + userOpCallData_ = abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_); userOp_ = createUserOp(address(deleGator_), userOpCallData_); userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(SignatureType.EOA, users.alice, userOpHash_.toEthSignedMessageHash()); @@ -121,7 +118,7 @@ contract HybridDeleGator_Test is BaseTest { submitUserOp_Bundler(userOp_); // Assert DeleGator is MultiSig - assertEq(address(IDeleGatorCoreFull(deleGator_).getImplementation()), address(multiSigDeleGatorImpl)); + assertEq(address(DeleGatorCore(deleGator_).getImplementation()), address(multiSigDeleGatorImpl)); // Assert Hybrid storage was cleared bytes32 DEFAULT_HYBRID_DELEGATOR_STORAGE_LOCATION = StorageUtilsLib.getStorageLocation("DeleGator.HybridDeleGator"); @@ -148,18 +145,18 @@ contract HybridDeleGator_Test is BaseTest { vm.deal(deleGator_, 100 ether); // Assert DeleGator is MultiSig - assertEq(address(IDeleGatorCoreFull(deleGator_).getImplementation()), address(multiSigDeleGatorImpl)); + assertEq(address(DeleGatorCore(deleGator_).getImplementation()), address(multiSigDeleGatorImpl)); // Upgrade to Hybrid - Action memory action_ = Action({ - to: address(deleGator_), + Execution memory execution_ = Execution({ + target: address(deleGator_), value: 0, - data: abi.encodeWithSelector( - IDeleGatorCoreFull.upgradeToAndCallAndRetainStorage.selector, + callData: abi.encodeWithSelector( + DeleGatorCore.upgradeToAndCallAndRetainStorage.selector, address(hybridDeleGatorImpl), abi.encodeWithSelector( HybridDeleGator.reinitialize.selector, - IDeleGatorCoreFull(deleGator_).getInitializedVersion() + 1, + DeleGatorCore(deleGator_).getInitializedVersion() + 1, users.alice.addr, new string[](0), new uint256[](0), @@ -168,7 +165,7 @@ contract HybridDeleGator_Test is BaseTest { ) ) }); - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, action_); + bytes memory userOpCallData_ = abi.encodeWithSignature(EXECUTE_SINGULAR_SIGNATURE, execution_); PackedUserOperation memory userOp_ = createUserOp(address(deleGator_), userOpCallData_); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(SignatureType.MultiSig, users.alice, userOpHash_.toEthSignedMessageHash()); @@ -176,7 +173,7 @@ contract HybridDeleGator_Test is BaseTest { submitUserOp_Bundler(userOp_); // Assert DeleGator is Hybrid - assertEq(address(IDeleGatorCoreFull(deleGator_).getImplementation()), address(hybridDeleGatorImpl)); + assertEq(address(DeleGatorCore(deleGator_).getImplementation()), address(hybridDeleGatorImpl)); // Assert MultiSig storage was not cleared bytes32 DEFAULT_MULTISIG_DELEGATOR_STORAGE_LOCATION = StorageUtilsLib.getStorageLocation("DeleGator.MultiSigDeleGator"); diff --git a/test/enforcers/AllowedCalldataEnforcer.t.sol b/test/enforcers/AllowedCalldataEnforcer.t.sol index 93f3924..b845486 100644 --- a/test/enforcers/AllowedCalldataEnforcer.t.sol +++ b/test/enforcers/AllowedCalldataEnforcer.t.sol @@ -4,9 +4,11 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { BytesLib } from "@bytes-utils/BytesLib.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import { Counter } from "../utils/Counter.t.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { AllowedCalldataEnforcer } from "../../src/enforcers/AllowedCalldataEnforcer.sol"; import { IDelegationManager } from "../../src/interfaces/IDelegationManager.sol"; @@ -21,10 +23,13 @@ contract DummyContract { } contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// AllowedCalldataEnforcer public allowedCalldataEnforcer; BasicERC20 public basicCF20; BasicCF721 public basicCF721; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -40,12 +45,13 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { // should allow a single method to be called when a single function parameter is equal function test_singleMethodCanBeCalledWithEqualParam() public { - // Create the action that would be executed - Action memory action_ = Action({ - to: address(basicCF20), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(basicCF20), value: 0, - data: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(100)) + callData: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(100)) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator uint256 paramStart_ = abi.encodeWithSelector(BasicERC20.mint.selector, address(0)).length; @@ -53,7 +59,7 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { bytes memory inputTerms_ = abi.encodePacked(paramStart_, paramValue_); vm.prank(address(delegationManager)); - allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should allow a method to be called when a single function parameter that is a dynamic array @@ -62,52 +68,55 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { param[0] = 1; param[1] = 2; - // Create the action that would be executed - Action memory action_ = - Action({ to: address(0), value: 0, data: abi.encodeWithSelector(DummyContract.arrayFn.selector, param) }); + // Create the execution that would be executed + Execution memory execution_ = + Execution({ target: address(0), value: 0, callData: abi.encodeWithSelector(DummyContract.arrayFn.selector, param) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // The subset of the calldata that includes the index of the calldata where the dynamic array starts bytes memory offsetTerms_ = abi.encodePacked(uint256(4), uint256(32)); // The subset of the calldata that includes the number of elements in the array bytes memory lengthTerms_ = abi.encodePacked(uint256(36), uint256(2)); // The subset of the calldata that includes data in the array - bytes memory parameterTerms_ = abi.encodePacked(uint256(68), BytesLib.slice(action_.data, uint256(68), uint256(64))); + bytes memory parameterTerms_ = abi.encodePacked(uint256(68), BytesLib.slice(execution_.callData, uint256(68), uint256(64))); vm.prank(address(delegationManager)); - allowedCalldataEnforcer.beforeHook(offsetTerms_, hex"", action_, keccak256(""), address(0), address(0)); - allowedCalldataEnforcer.beforeHook(lengthTerms_, hex"", action_, keccak256(""), address(0), address(0)); - allowedCalldataEnforcer.beforeHook(parameterTerms_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(offsetTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(lengthTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(parameterTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should allow a single method to be called when a single function parameter that is dynamic is equal function test_singleMethodCanBeCalledWithEqualDynamicStringParam() public { string memory param = "Test string"; - // Create the action that would be executed - Action memory action_ = - Action({ to: address(0), value: 0, data: abi.encodeWithSelector(DummyContract.arrayFn.selector, param) }); + // Create the execution that would be executed + Execution memory execution_ = + Execution({ target: address(0), value: 0, callData: abi.encodeWithSelector(DummyContract.arrayFn.selector, param) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // The offset of the string in the calldata bytes memory offsetTerms_ = abi.encodePacked(uint256(4), uint256(32)); // The length of the string bytes memory lengthTerms_ = abi.encodePacked(uint256(36), uint256(11)); // The string itself - bytes memory parameterTerms_ = abi.encodePacked(uint256(68), BytesLib.slice(action_.data, uint256(68), uint256(32))); + bytes memory parameterTerms_ = abi.encodePacked(uint256(68), BytesLib.slice(execution_.callData, uint256(68), uint256(32))); vm.prank(address(delegationManager)); - allowedCalldataEnforcer.beforeHook(offsetTerms_, hex"", action_, keccak256(""), address(0), address(0)); - allowedCalldataEnforcer.beforeHook(lengthTerms_, hex"", action_, keccak256(""), address(0), address(0)); - allowedCalldataEnforcer.beforeHook(parameterTerms_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(offsetTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(lengthTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(parameterTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should allow Artist to create NFT specific delegations with metadata caveat function test_methodCanBeCalledWithSpecificMetadata() public { string memory metadataUrl_ = "ipfs://bafybeigxsy55qgbdqw44y5yrs2jhhk2kdn7vbt6y4myvhcwdjak6cwj464/3762"; - // The Action with the mint calldata that would be executed + // The Execution with the mint calldata that would be executed bytes memory encodedData_ = abi.encodeWithSelector(BasicCF721.mintWithMetadata.selector, address(users.bob.deleGator), metadataUrl_); - Action memory action_ = Action({ to: address(basicCF721), value: 0, data: encodedData_ }); + Execution memory execution_ = Execution({ target: address(basicCF721), value: 0, callData: encodedData_ }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Calculate the start and length of the metadata bytes within the calldata bytes memory encodedMetadataString_ = abi.encode(metadataUrl_); @@ -117,19 +126,20 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); // NOTE: Using encodedData_ not encodedMetadataString_ to ensure the value for the offset is correct bytes memory allowedCalldata_ = abi.encodePacked(start_, BytesLib.slice(encodedData_, uint256(start_), uint256(length_))); - allowedCalldataEnforcer.beforeHook(allowedCalldata_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(allowedCalldata_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } ////////////////////// Invalid cases ////////////////////// // should NOT allow a method to be called when a single function parameter is not equal function test_singleMethodCanNotCalledWithNonEqualParam() public { - // Create the action that would be executed - Action memory action_ = Action({ - to: address(basicCF20), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(basicCF20), value: 0, - data: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(200)) + callData: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(200)) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator uint256 paramStart_ = abi.encodeWithSelector(BasicERC20.mint.selector, address(0)).length; @@ -138,17 +148,18 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("AllowedCalldataEnforcer:invalid-calldata"); - allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should NOT allow to pass an invalid calldata length (invalid terms) function test_failsWithInvalidTermsLength() public { - // Create the action that would be executed - Action memory action_ = Action({ - to: address(basicCF20), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(basicCF20), value: 0, - data: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(200)) + callData: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(200)) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator uint256 paramStart_ = abi.encodeWithSelector(BasicERC20.mint.selector, address(0)).length; @@ -157,17 +168,18 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("AllowedCalldataEnforcer:invalid-calldata-length"); - allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should NOT allow a method to be called when a terms size is invalid function test_singleMethodCanNotCalledWithInvalidTermsSize() public { - // Create the action that would be executed - Action memory action_ = Action({ - to: address(basicCF20), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(basicCF20), value: 0, - data: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(200)) + callData: abi.encodeWithSelector(BasicERC20.mint.selector, address(users.alice.deleGator), uint256(200)) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator uint256 paramStart_ = abi.encodeWithSelector(BasicERC20.mint.selector, address(0)).length; @@ -175,7 +187,7 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("AllowedCalldataEnforcer:invalid-terms-size"); - allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + allowedCalldataEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } ////////////////////// Integration ////////////////////// @@ -184,11 +196,11 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { function test_singleMethodCanBeCalledWithEqualParamIntegration() public { assertEq(basicCF20.balanceOf(address(users.bob.deleGator)), 0); - // Create the action that would be executed on Alice for transferring a ft tokens - Action memory action1_ = Action({ - to: address(basicCF20), + // Create the execution that would be executed on Alice for transferring a ft tokens + Execution memory execution1_ = Execution({ + target: address(basicCF20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(1)) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(1)) }); // create terms for the enforcer @@ -214,13 +226,13 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation_; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action1_); + invokeDelegation_UserOp(users.bob, delegations_, execution1_); // Validate that the balance have increased assertEq(basicCF20.balanceOf(address(users.bob.deleGator)), uint256(1)); // Enforcer allows to reuse the delegation - invokeDelegation_UserOp(users.bob, delegations_, action1_); + invokeDelegation_UserOp(users.bob, delegations_, execution1_); // Validate that the balance has increased again assertEq(basicCF20.balanceOf(address(users.bob.deleGator)), uint256(2)); @@ -230,11 +242,11 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { function test_singleMethodCanNotBeCalledWithNonEqualParamIntegration() public { assertEq(basicCF20.balanceOf(address(users.bob.deleGator)), 0); - // Create the action that would be executed on Alice for transferring a ft tokens - Action memory action1_ = Action({ - to: address(basicCF20), + // Create the execution that would be executed on Alice for transferring a ft tokens + Execution memory execution1_ = Execution({ + target: address(basicCF20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(2)) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(2)) }); // create terms for the enforcer @@ -260,7 +272,7 @@ contract AllowedCalldataEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation_; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action1_); + invokeDelegation_UserOp(users.bob, delegations_, execution1_); // Validate that the balance have not increased assertEq(basicCF20.balanceOf(address(users.bob.deleGator)), uint256(0)); diff --git a/test/enforcers/AllowedMethodsEnforcer.t.sol b/test/enforcers/AllowedMethodsEnforcer.t.sol index 1cd32f9..5e179cb 100644 --- a/test/enforcers/AllowedMethodsEnforcer.t.sol +++ b/test/enforcers/AllowedMethodsEnforcer.t.sol @@ -3,8 +3,10 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { AllowedMethodsEnforcer } from "../../src/enforcers/AllowedMethodsEnforcer.sol"; @@ -13,9 +15,12 @@ import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////// State ////////////////////// AllowedMethodsEnforcer public allowedMethodsEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -29,29 +34,38 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { // should allow a method to be called when a single method is allowed function test_singleMethodCanBeCalled() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); allowedMethodsEnforcer.beforeHook( - abi.encodePacked(Counter.increment.selector), hex"", action_, keccak256(""), address(0), address(0) + abi.encodePacked(Counter.increment.selector), hex"", mode, executionCallData_, keccak256(""), address(0), address(0) ); } // should allow a method to be called when a multiple methods are allowed function test_multiMethodCanBeCalled() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); allowedMethodsEnforcer.beforeHook( abi.encodePacked(Counter.setCount.selector, Ownable.renounceOwnership.selector, Counter.increment.selector), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -66,18 +80,21 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { allowedMethodsEnforcer.getTermsInfo(bytes("1")); } - // should FAIL if action.data length < 4 - function test_notAllow_invalidActionLength() public { - // Create the action that would be executed - Action memory action_ = Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodePacked(true) }); + // should FAIL if execution.callData length < 4 + function test_notAllow_invalidExecutionLength() public { + // Create the execution that would be executed + Execution memory execution_ = + Execution({ target: address(aliceDeleGatorCounter), value: 0, callData: abi.encodePacked(true) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); - vm.expectRevert("AllowedMethodsEnforcer:invalid-action-data-length"); + vm.expectRevert("AllowedMethodsEnforcer:invalid-execution-data-length"); allowedMethodsEnforcer.beforeHook( abi.encodePacked(Counter.setCount.selector, Ownable.renounceOwnership.selector, Ownable.owner.selector), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -86,9 +103,13 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { // should NOT allow a method to be called when the method is not allowed function test_onlyApprovedMethodsCanBeCalled() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); @@ -96,7 +117,8 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { allowedMethodsEnforcer.beforeHook( abi.encodePacked(Counter.setCount.selector, Ownable.renounceOwnership.selector, Ownable.owner.selector), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -109,9 +131,12 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { function test_methodCanBeSingleMethodIntegration() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = @@ -132,14 +157,14 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation_; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get count uint256 valueAfter_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 assertEq(valueAfter_, initialValue_ + 1); // Enforcer allows to reuse the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has increased again @@ -150,9 +175,12 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { function test_onlyApprovedMethodsCanBeCalledIntegration() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ @@ -176,7 +204,7 @@ contract AllowedMethodsEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation_; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 valueAfter_ = aliceDeleGatorCounter.count(); // Validate that the count has not changed diff --git a/test/enforcers/AllowedTargetsEnforcer.t.sol b/test/enforcers/AllowedTargetsEnforcer.t.sol index 3f35074..585993b 100644 --- a/test/enforcers/AllowedTargetsEnforcer.t.sol +++ b/test/enforcers/AllowedTargetsEnforcer.t.sol @@ -2,8 +2,10 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { AllowedTargetsEnforcer } from "../../src/enforcers/AllowedTargetsEnforcer.sol"; @@ -13,10 +15,13 @@ import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; import { BasicERC20, IERC20 } from "../utils/BasicERC20.t.sol"; contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// AllowedTargetsEnforcer public allowedTargetsEnforcer; BasicERC20 public testFToken1; BasicERC20 public testFToken2; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -32,29 +37,38 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { // should allow a method to be called when a single target is allowed function test_singleTargetCanBeCalled() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); allowedTargetsEnforcer.beforeHook( - abi.encodePacked(address(aliceDeleGatorCounter)), hex"", action_, keccak256(""), address(0), address(0) + abi.encodePacked(address(aliceDeleGatorCounter)), hex"", mode, executionCallData_, keccak256(""), address(0), address(0) ); } // should allow a method to be called when a multiple targets are allowed function test_multiTargetCanBeCalled() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); allowedTargetsEnforcer.beforeHook( abi.encodePacked(address(bobDeleGatorCounter), address(carolDeleGatorCounter), address(aliceDeleGatorCounter)), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -71,9 +85,13 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { // should NOT allow a method to be called when the target is not allowed function test_onlyApprovedTargetsCanBeCalled() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(daveDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(daveDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Dave's DeleGator vm.prank(address(delegationManager)); @@ -81,7 +99,8 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { allowedTargetsEnforcer.beforeHook( abi.encodePacked(address(bobDeleGatorCounter), address(carolDeleGatorCounter), address(aliceDeleGatorCounter)), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -95,15 +114,18 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { assertEq(aliceDeleGatorCounter.count(), 0); assertEq(testFToken1.balanceOf(address(users.bob.deleGator)), 0); - // Create the action that would be executed on Alice for incrementing the count - Action memory action1_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed on Alice for incrementing the count + Execution memory execution1_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); - // Create the action that would be executed on Alice for transferring a ft tokens - Action memory action2_ = Action({ - to: address(testFToken1), + // Create the execution that would be executed on Alice for transferring a ft tokens + Execution memory execution2_ = Execution({ + target: address(testFToken1), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), 1 ether) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), 1 ether) }); Caveat[] memory caveats_ = new Caveat[](1); @@ -128,16 +150,16 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation_; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action1_); - invokeDelegation_UserOp(users.bob, delegations_, action2_); + invokeDelegation_UserOp(users.bob, delegations_, execution1_); + invokeDelegation_UserOp(users.bob, delegations_, execution2_); // Validate that the count and balance have increased assertEq(aliceDeleGatorCounter.count(), 1); assertEq(testFToken1.balanceOf(address(users.bob.deleGator)), 1 ether); // Enforcer allows to reuse the delegation - invokeDelegation_UserOp(users.bob, delegations_, action1_); - invokeDelegation_UserOp(users.bob, delegations_, action2_); + invokeDelegation_UserOp(users.bob, delegations_, execution1_); + invokeDelegation_UserOp(users.bob, delegations_, execution2_); // Validate that the count and balance has increased again assertEq(aliceDeleGatorCounter.count(), 2); @@ -149,11 +171,11 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { assertEq(testFToken1.balanceOf(address(users.bob.deleGator)), 0); assertEq(testFToken2.balanceOf(address(users.bob.deleGator)), 0); - // Create the action that would be executed on Alice for transferring FToken2 - Action memory action_ = Action({ - to: address(testFToken2), + // Create the execution that would be executed on Alice for transferring FToken2 + Execution memory execution_ = Execution({ + target: address(testFToken2), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), 1 ether) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), 1 ether) }); // Approving the user to use the FToken1 @@ -176,7 +198,7 @@ contract AllowedTargetsEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation_; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the balances on both FTokens has not increased assertEq(testFToken1.balanceOf(address(users.bob.deleGator)), 0); diff --git a/test/enforcers/ArgsEqualityCheckEnforcer.t.sol b/test/enforcers/ArgsEqualityCheckEnforcer.t.sol index 2816ce4..5588682 100644 --- a/test/enforcers/ArgsEqualityCheckEnforcer.t.sol +++ b/test/enforcers/ArgsEqualityCheckEnforcer.t.sol @@ -1,15 +1,20 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; + import "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { ArgsEqualityCheckEnforcer } from "../../src/enforcers/ArgsEqualityCheckEnforcer.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract ArgsEqualityCheckEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////// State ////////////////////// ArgsEqualityCheckEnforcer public argsEqualityCheckEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -25,7 +30,9 @@ contract ArgsEqualityCheckEnforcerTest is CaveatEnforcerBaseTest { function test_passEnforcerWhenTermsEqualsArgs() public { bytes memory terms_ = bytes("This is an example"); bytes memory args_ = bytes("This is an example"); - argsEqualityCheckEnforcer.beforeHook(terms_, args_, new Action[](1)[0], bytes32(0), address(0), address(0)); + argsEqualityCheckEnforcer.beforeHook( + terms_, args_, mode, abi.encode(new Execution[](1)[0]), bytes32(0), address(0), address(0) + ); } ////////////////////// Invalid cases ////////////////////// @@ -39,7 +46,9 @@ contract ArgsEqualityCheckEnforcerTest is CaveatEnforcerBaseTest { vm.expectRevert("ArgsEqualityCheckEnforcer:different-args-and-terms"); vm.expectEmit(true, true, true, true, address(argsEqualityCheckEnforcer)); emit ArgsEqualityCheckEnforcer.DifferentArgsAndTerms(address(delegationManager), redeemer_, bytes32(0), terms_, args_); - argsEqualityCheckEnforcer.beforeHook(terms_, args_, new Action[](1)[0], bytes32(0), address(0), redeemer_); + argsEqualityCheckEnforcer.beforeHook( + terms_, args_, mode, abi.encode(new Execution[](1)[0]), bytes32(0), address(0), redeemer_ + ); } function _getEnforcer() internal view override returns (ICaveatEnforcer) { diff --git a/test/enforcers/BlockNumberEnforcer.t.sol b/test/enforcers/BlockNumberEnforcer.t.sol index 43c3f79..c5eb7bc 100644 --- a/test/enforcers/BlockNumberEnforcer.t.sol +++ b/test/enforcers/BlockNumberEnforcer.t.sol @@ -3,8 +3,10 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { BlockNumberEnforcer } from "../../src/enforcers/BlockNumberEnforcer.sol"; @@ -16,6 +18,7 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { ////////////////////// State ////////////////////// BlockNumberEnforcer public blockNumberEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -29,40 +32,55 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { // should SUCCEED to INVOKE method AFTER blockNumber reached function test_methodCanBeCalledAfterBlockNumber() public { - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + vm.roll(10000); uint128 blockAfterThreshold_ = 1; uint128 blockBeforeThreshold_ = 0; // Not using before threshold bytes memory inputTerms_ = abi.encodePacked(blockAfterThreshold_, blockBeforeThreshold_); vm.prank(address(delegationManager)); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } //should SUCCEED to INVOKE method BEFORE blockNumber reached function test_methodCanBeCalledBeforeBlockNumber() public { - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 blockAfterThreshold_ = 0; // Not using after threshold uint128 blockBeforeThreshold_ = uint128(block.number + 10000); bytes memory inputTerms_ = abi.encodePacked(blockAfterThreshold_, blockBeforeThreshold_); vm.prank(address(delegationManager)); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should SUCCEED to INVOKE method inside blockNumber RANGE function test_methodCanBeCalledInsideBlockNumberRange() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 blockAfterThreshold_ = 1; uint128 blockBeforeThreshold_ = uint128(block.number + 10000); vm.roll(1000); // making block number between 1 and 10001 bytes memory inputTerms_ = abi.encodePacked(blockAfterThreshold_, blockBeforeThreshold_); vm.prank(address(delegationManager)); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } ////////////////////// Invalid cases ////////////////////// @@ -75,9 +93,13 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { // should FAIL to INVOKE method BEFORE blockNumber reached function test_methodFailsIfCalledBeforeBlockNumber() public { - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); uint128 blockAfterThreshold_ = uint128(block.number + 10000); uint128 blockBeforeThreshold_ = 0; // Not using before threshold @@ -85,14 +107,19 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("BlockNumberEnforcer:early-delegation"); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE method AFTER blockNumber reached function test_methodFailsIfCalledAfterBlockNumber() public { - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 blockAfterThreshold_ = 0; // Not using after threshold uint128 blockBeforeThreshold_ = uint128(block.number); vm.roll(10000); @@ -100,28 +127,38 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("BlockNumberEnforcer:expired-delegation"); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE method BEFORE blocknumber RANGE function test_methodFailsIfCalledBeforeBlockNumberRange() public { - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 blockAfterThreshold_ = uint128(block.number + 10000); uint128 blockBeforeThreshold_ = uint128(block.number + 20000); bytes memory inputTerms_ = abi.encodePacked(blockAfterThreshold_, blockBeforeThreshold_); vm.prank(address(delegationManager)); vm.expectRevert("BlockNumberEnforcer:early-delegation"); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE method AFTER blocknumber RANGE" function test_methodFailsIfCalledAfterBlockNumberRange() public { - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 blockAfterThreshold_ = uint128(block.number + 10000); uint128 blockBeforeThreshold_ = uint128(block.number + 20000); vm.roll(30000); @@ -129,7 +166,7 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("BlockNumberEnforcer:expired-delegation"); - blockNumberEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + blockNumberEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } ////////////////////// Integration ////////////////////// @@ -137,9 +174,12 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { // should SUCCEED to INVOKE until reaching blockNumber function test_methodCanBeCalledAfterBlockNumberIntegration() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action_ that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); vm.roll(10); // Not using before threshold (blockAfterThreshold_ = 1, blockBeforeThreshold_ = 100) bytes memory inputTerms_ = abi.encodePacked(uint128(1), uint128(100)); @@ -162,7 +202,7 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 valueAfter_ = aliceDeleGatorCounter.count(); // Validate that the count has increased by 1 @@ -170,7 +210,7 @@ contract BlockNumberEnforcerTest is CaveatEnforcerBaseTest { // Enforcer blocks the delegation vm.roll(100); - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased by 1 diff --git a/test/enforcers/DeployedEnforcer.t.sol b/test/enforcers/DeployedEnforcer.t.sol index b642789..870b179 100644 --- a/test/enforcers/DeployedEnforcer.t.sol +++ b/test/enforcers/DeployedEnforcer.t.sol @@ -2,8 +2,10 @@ pragma solidity 0.8.23; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { DeployedEnforcer } from "../../src/enforcers/DeployedEnforcer.sol"; import { IDelegationManager } from "../../src/interfaces/IDelegationManager.sol"; @@ -11,10 +13,13 @@ import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract DeployedEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// DeployedEnforcer public deployedEnforcer; bytes32 public salt; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////////////// Events ////////////////////////////// @@ -46,9 +51,13 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { bytes32 bytecodeHash_ = hashInitCode(type(Counter).creationCode); address predictedAddr_ = vm.computeCreate2Address(salt, bytecodeHash_, address(deployedEnforcer)); - // NOTE: Action isn't very relevant for this test. - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Check that the contract hasn't been deployed yet bytes memory initialCode_ = predictedAddr_.code; @@ -63,7 +72,8 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { deployedEnforcer.beforeHook( abi.encodePacked(predictedAddr_, salt, abi.encodePacked(type(Counter).creationCode)), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -81,14 +91,24 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { bytes32 bytecodeHash_ = hashInitCode(bytecode_); address predictedAddr_ = vm.computeCreate2Address(salt, bytecodeHash_, address(deployedEnforcer)); - // NOTE: Action isn't very relevant for this test. - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Deploy the contract vm.prank(address(delegationManager)); deployedEnforcer.beforeHook( - abi.encodePacked(predictedAddr_, salt, bytecode_), hex"", action_, keccak256(""), address(0), address(0) + abi.encodePacked(predictedAddr_, salt, bytecode_), + hex"", + mode, + executionCallData_, + keccak256(""), + address(0), + address(0) ); // beforeHook, mimicking the behavior of Alice's DeleGator @@ -98,7 +118,13 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { // Use enforcer when contract is already deployed deployedEnforcer.beforeHook( - abi.encodePacked(predictedAddr_, salt, bytecode_), hex"", action_, keccak256(""), address(0), address(0) + abi.encodePacked(predictedAddr_, salt, bytecode_), + hex"", + mode, + executionCallData_, + keccak256(""), + address(0), + address(0) ); } @@ -106,9 +132,13 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { // should revert if the predicted address doesn't match the deployed address function test_revertIfPredictedAddressDoesNotMatch() public { - // NOTE: Action isn't very relevant for this test. - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); @@ -116,7 +146,8 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { deployedEnforcer.beforeHook( abi.encodePacked(users.alice.addr, salt, abi.encodePacked(type(Counter).creationCode)), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -125,24 +156,36 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { // should revert if the length of the terms is not sufficient function test_revertIfTermsLengthIsInvalid() public { - // NOTE: Action isn't very relevant for this test. - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); vm.startPrank(address(delegationManager)); // 0 bytes vm.expectRevert("DeployedEnforcer:invalid-terms-length"); - deployedEnforcer.beforeHook(hex"", hex"", action_, keccak256(""), address(0), address(0)); + deployedEnforcer.beforeHook(hex"", hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); // 20 bytes vm.expectRevert("DeployedEnforcer:invalid-terms-length"); - deployedEnforcer.beforeHook(abi.encodePacked(users.alice.addr), hex"", action_, keccak256(""), address(0), address(0)); + deployedEnforcer.beforeHook( + abi.encodePacked(users.alice.addr), hex"", mode, executionCallData_, keccak256(""), address(0), address(0) + ); // 52 bytes vm.expectRevert("DeployedEnforcer:invalid-terms-length"); deployedEnforcer.beforeHook( - abi.encodePacked(users.alice.addr, bytes32(hex"")), hex"", action_, keccak256(""), address(0), address(0) + abi.encodePacked(users.alice.addr, bytes32(hex"")), + hex"", + mode, + executionCallData_, + keccak256(""), + address(0), + address(0) ); } @@ -154,15 +197,25 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { bytes32 bytecodeHash_ = hashInitCode(bytecode_); address predictedAddr_ = vm.computeCreate2Address(salt, bytecodeHash_, address(deployedEnforcer)); - // // NOTE: Action isn't very relevant for this test. - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // beforeHook, mimicking the behavior of Alice's DeleGator vm.prank(address(delegationManager)); vm.expectRevert(abi.encodeWithSelector(DeployedEnforcer.DeployedEmptyContract.selector, predictedAddr_)); deployedEnforcer.beforeHook( - abi.encodePacked(predictedAddr_, salt, bytecode_), hex"", action_, keccak256(""), address(0), address(0) + abi.encodePacked(predictedAddr_, salt, bytecode_), + hex"", + mode, + executionCallData_, + keccak256(""), + address(0), + address(0) ); } @@ -174,9 +227,13 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { bytes32 bytecodeHash_ = hashInitCode(hex""); address predictedAddr_ = vm.computeCreate2Address(salt, bytecodeHash_, address(deployedEnforcer)); - // NOTE: Action isn't very relevant for this test. - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Check that the contract hasn't been deployed yet bytes memory initialCode_ = predictedAddr_.code; @@ -188,7 +245,8 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { deployedEnforcer.beforeHook( abi.encodePacked(predictedAddr_, salt, abi.encodePacked(type(Counter).creationCode)), hex"", - action_, + mode, + executionCallData_, keccak256(""), address(0), address(0) @@ -203,8 +261,10 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { bytes32 bytecodeHash_ = hashInitCode(type(Counter).creationCode); address predictedAddr_ = vm.computeCreate2Address(salt, bytecodeHash_, address(deployedEnforcer)); - // NOTE: Action isn't very relevant for this test. - Action memory action_ = Action({ to: predictedAddr_, value: 0, data: abi.encodeWithSelector(Counter.setCount.selector, 1) }); + // NOTE: Execution isn't very relevant for this test. + Execution memory execution_ = + Execution({ target: predictedAddr_, value: 0, callData: abi.encodeWithSelector(Counter.setCount.selector, 1) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Check that the contract hasn't been deployed yet bytes memory initialCode_ = predictedAddr_.code; @@ -232,7 +292,7 @@ contract DeployedEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Check that the contract has been deployed properly bytes memory finalCode_ = predictedAddr_.code; diff --git a/test/enforcers/ERC20BalanceGteEnforcer.t.sol b/test/enforcers/ERC20BalanceGteEnforcer.t.sol index 7776891..48362e8 100644 --- a/test/enforcers/ERC20BalanceGteEnforcer.t.sol +++ b/test/enforcers/ERC20BalanceGteEnforcer.t.sol @@ -3,22 +3,26 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { BasicERC20 } from "../utils/BasicERC20.t.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { ERC20BalanceGteEnforcer } from "../../src/enforcers/ERC20BalanceGteEnforcer.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// ERC20BalanceGteEnforcer public enforcer; BasicERC20 public token; address delegator; address delegate; address dm; - Action noAction; - Action mintAction; + Execution mintExecution; + bytes mintExecutionCallData; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -31,8 +35,9 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { vm.label(address(enforcer), "ERC20 BalanceGte Enforcer"); token = new BasicERC20(delegator, "TEST", "TEST", 0); vm.label(address(token), "ERC20 Test Token"); - mintAction = Action({ to: address(token), value: 0, data: abi.encodeWithSelector(token.mint.selector, delegator, 100) }); - noAction = Action(address(0), 0, hex""); + mintExecution = + Execution({ target: address(token), value: 0, callData: abi.encodeWithSelector(token.mint.selector, delegator, 100) }); + mintExecutionCallData = abi.encode(mintExecution); } ////////////////////// Basic Functionality ////////////////////// @@ -54,19 +59,19 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase by 100 vm.prank(dm); - enforcer.beforeHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); vm.prank(delegator); token.mint(delegator, 100); vm.prank(dm); - enforcer.afterHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); // Increase by 1000 vm.prank(dm); - enforcer.beforeHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); vm.prank(delegator); token.mint(delegator, 1000); vm.prank(dm); - enforcer.afterHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); } // ////////////////////// Errors ////////////////////// @@ -78,12 +83,12 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase by 10, expect revert vm.prank(dm); - enforcer.beforeHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); vm.prank(delegator); token.mint(delegator, 10); vm.prank(dm); vm.expectRevert(bytes("ERC20BalanceGteEnforcer:balance-not-gt")); - enforcer.afterHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); } // Reverts if a enforcer is locked @@ -95,20 +100,20 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase by 100 vm.startPrank(dm); // Locks the enforcer - enforcer.beforeHook(terms_, hex"", mintAction, delegationHash_, delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, delegationHash_, delegator, delegate); bytes32 hashKey_ = enforcer.getHashKey(address(delegationManager), address(token), delegationHash_); assertTrue(enforcer.isLocked(hashKey_)); vm.expectRevert(bytes("ERC20BalanceGteEnforcer:enforcer-is-locked")); - enforcer.beforeHook(terms_, hex"", mintAction, delegationHash_, delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, delegationHash_, delegator, delegate); vm.startPrank(delegator); token.mint(delegator, 1000); vm.startPrank(dm); // Unlocks the enforcer - enforcer.afterHook(terms_, hex"", mintAction, delegationHash_, delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, mintExecutionCallData, delegationHash_, delegator, delegate); assertFalse(enforcer.isLocked(hashKey_)); // Can be used again, and locks it again - enforcer.beforeHook(terms_, hex"", mintAction, delegationHash_, delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, delegationHash_, delegator, delegate); assertTrue(enforcer.isLocked(hashKey_)); } @@ -134,7 +139,7 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Invalid token terms_ = abi.encodePacked(address(0), uint256(100)); vm.expectRevert(); - enforcer.beforeHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); } // Validates that an invalid ID reverts @@ -144,9 +149,9 @@ contract ERC20BalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase vm.prank(dm); - enforcer.beforeHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); vm.expectRevert(); - enforcer.afterHook(terms_, hex"", mintAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, mintExecutionCallData, bytes32(0), delegator, delegate); } ////////////////////// Integration ////////////////////// diff --git a/test/enforcers/ERC20TransferAmountEnforcer.t.sol b/test/enforcers/ERC20TransferAmountEnforcer.t.sol index d8f0572..dc4ca88 100644 --- a/test/enforcers/ERC20TransferAmountEnforcer.t.sol +++ b/test/enforcers/ERC20TransferAmountEnforcer.t.sol @@ -2,8 +2,10 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { ERC20TransferAmountEnforcer } from "../../src/enforcers/ERC20TransferAmountEnforcer.sol"; @@ -13,10 +15,13 @@ import { IDelegationManager } from "../../src/interfaces/IDelegationManager.sol" import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// ERC20TransferAmountEnforcer public erc20TransferAmountEnforcer; BasicERC20 public basicERC20; BasicERC20 public invalidERC20; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////////////// Events ////////////////////////////// event IncreasedSpentMap( @@ -38,12 +43,14 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { function test_transferSucceedsIfCalledBelowAllowance() public { uint256 spendingLimit_ = 1 ether; - // Create the action that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), spendingLimit_) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), spendingLimit_) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory inputTerms_ = abi.encodePacked(address(basicERC20), spendingLimit_); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -61,7 +68,9 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectEmit(true, true, true, true, address(erc20TransferAmountEnforcer)); emit IncreasedSpentMap(address(delegationManager), address(0), delegationHash_, spendingLimit_, 1 ether); - erc20TransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + erc20TransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), spendingLimit_); } @@ -72,12 +81,14 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { function test_transferFailsIfCalledAboveAllowance() public { uint256 spendingLimit_ = 1 ether; - // Create the action that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(spendingLimit_ + 1)) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(spendingLimit_ + 1)) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory inputTerms_ = abi.encodePacked(address(basicERC20), spendingLimit_); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -95,7 +106,9 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("ERC20TransferAmountEnforcer:allowance-exceeded"); - erc20TransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + erc20TransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); } @@ -106,12 +119,14 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { function test_methodFailsIfInvokesInvalidContract() public { uint256 spendingLimit_ = 1 ether; - // Create the action_ that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), spendingLimit_) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), spendingLimit_) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory inputTerms_ = abi.encodePacked(address(invalidERC20), spendingLimit_); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -129,23 +144,27 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); vm.prank(address(delegationManager)); vm.expectRevert("ERC20TransferAmountEnforcer:invalid-contract"); - erc20TransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + erc20TransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); } - // should FAIL to INVOKE invalid action data length - function test_notAllow_invalidActionLength() public { + // should FAIL to INVOKE invalid execution data length + function test_notAllow_invalidExecutionLength() public { uint256 spendingLimit_ = 1 ether; - // Create the action_ that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector( + callData: abi.encodeWithSelector( IERC20.transferFrom.selector, address(users.alice.deleGator), address(users.bob.deleGator), spendingLimit_ ) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory inputTerms_ = abi.encodePacked(address(basicERC20), spendingLimit_); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -162,8 +181,10 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); vm.prank(address(delegationManager)); - vm.expectRevert("ERC20TransferAmountEnforcer:invalid-action-length"); - erc20TransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + vm.expectRevert("ERC20TransferAmountEnforcer:invalid-execution-length"); + erc20TransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); } @@ -172,12 +193,14 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { function test_methodFailsIfInvokesInvalidMethod() public { uint256 spendingLimit_ = 1 ether; - // Create the action_ that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector(IERC20.transferFrom.selector, address(users.bob.deleGator), spendingLimit_) + callData: abi.encodeWithSelector(IERC20.transferFrom.selector, address(users.bob.deleGator), spendingLimit_) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory inputTerms_ = abi.encodePacked(address(basicERC20), spendingLimit_); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -195,7 +218,9 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("ERC20TransferAmountEnforcer:invalid-method"); - erc20TransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + erc20TransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); } @@ -204,12 +229,14 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { function test_methodFailsIfInvokesInvalidTermsLength() public { uint256 spendingLimit_ = 1 ether; - // Create the action_ that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(spendingLimit_)) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), uint256(spendingLimit_)) }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory inputTerms_ = abi.encodePacked(address(basicERC20)); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -227,7 +254,9 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("ERC20TransferAmountEnforcer:invalid-terms-length"); - erc20TransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + erc20TransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); } @@ -238,12 +267,13 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { assertEq(basicERC20.balanceOf(address(users.alice.deleGator)), 100 ether); assertEq(basicERC20.balanceOf(address(users.bob.deleGator)), 0); - // Create the action_ that would be executed - Action memory action_ = Action({ - to: address(basicERC20), + // Create the execution_ that would be executed + Execution memory execution_ = Execution({ + target: address(basicERC20), value: 0, - data: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), 1 ether) + callData: abi.encodeWithSelector(IERC20.transfer.selector, address(users.bob.deleGator), 1 ether) }); + bytes memory inputTerms_ = abi.encodePacked(address(basicERC20), spendingLimit_); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(erc20TransferAmountEnforcer), terms: inputTerms_ }); @@ -266,7 +296,7 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate Alice balance 99 ether assertEq(_getFtBalanceOf(address(users.alice.deleGator)), 99 ether); @@ -275,7 +305,7 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 1 ether); // The delegation can be reused while the allowance is enough - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate Alice balance 98 ether assertEq(_getFtBalanceOf(address(users.alice.deleGator)), 98 ether); // Validate Bob balance 1 ether @@ -283,7 +313,7 @@ contract ERC20TransferAmountEnforcerTest is CaveatEnforcerBaseTest { assertEq(erc20TransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), spendingLimit_); // If allowance is not enough the transfer should not work - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate Balances did not change when transfer are above the allowance assertEq(_getFtBalanceOf(address(users.alice.deleGator)), 98 ether); assertEq(_getFtBalanceOf(address(users.bob.deleGator)), 2 ether); diff --git a/test/enforcers/IdEnforcer.t.sol b/test/enforcers/IdEnforcer.t.sol index b9d4c73..06c19b4 100644 --- a/test/enforcers/IdEnforcer.t.sol +++ b/test/enforcers/IdEnforcer.t.sol @@ -2,9 +2,11 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { IdEnforcer } from "../../src/enforcers/IdEnforcer.sol"; @@ -14,9 +16,12 @@ import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; import { BasicERC20, IERC20 } from "../utils/BasicERC20.t.sol"; contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// IdEnforcer public idEnforcer; BasicERC20 public testFToken1; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////////////// Events ////////////////////////////// @@ -40,7 +45,8 @@ contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { // Validates that the enforcer reverts and returns false once reusing the nonce function test_blocksDelegationWithRepeatedNonce() public { - Action memory action_; + Execution memory execution_; + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); uint256 id_ = uint256(123456789); bytes memory terms_ = abi.encode(id_); address delegator_ = address(users.alice.deleGator); @@ -53,7 +59,7 @@ contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { // First usage works well vm.expectEmit(true, true, true, true, address(idEnforcer)); emit UsedId(address(delegationManager), address(0), delegator_, id_); - idEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), delegator_, address(0)); + idEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), delegator_, address(0)); // After the first usage the enforcer marks the nonce as used. assertTrue(idEnforcer.getIsUsed(address(delegationManager), delegator_, id_)); @@ -61,19 +67,20 @@ contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { // Second usage reverts, and returns false. vm.expectRevert("IdEnforcer:id-already-used"); - idEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), delegator_, address(0)); + idEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), delegator_, address(0)); } // should FAIL to INVOKE with invalid input terms function test_methodFailsIfCalledWithInvalidInputTerms() public { - Action memory action_; + Execution memory execution_; + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory terms_ = abi.encodePacked(uint32(1)); vm.expectRevert("IdEnforcer:invalid-terms-length"); - idEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), address(0), address(0)); + idEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), address(0), address(0)); terms_ = abi.encodePacked(uint256(1), uint256(1)); vm.expectRevert("IdEnforcer:invalid-terms-length"); - idEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), address(0), address(0)); + idEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), address(0), address(0)); } ////////////////////// Integration ////////////////////// @@ -81,9 +88,12 @@ contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { // Should revert to use a delegation which nonce has already been used function test_methodFailsIfNonceAlreadyUsed() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); bytes memory inputTerms_ = abi.encode(uint256(12345)); @@ -105,12 +115,12 @@ contract IdEnforcerEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has increased by 1 assertEq(aliceDeleGatorCounter.count(), initialValue_ + 1); // Enforcer blocks the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has not increased by 1 assertEq(aliceDeleGatorCounter.count(), initialValue_ + 1); } diff --git a/test/enforcers/LimitedCallsEnforcer.t.sol b/test/enforcers/LimitedCallsEnforcer.t.sol index a77a914..c07edd5 100644 --- a/test/enforcers/LimitedCallsEnforcer.t.sol +++ b/test/enforcers/LimitedCallsEnforcer.t.sol @@ -2,9 +2,11 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { LimitedCallsEnforcer } from "../../src/enforcers/LimitedCallsEnforcer.sol"; @@ -13,6 +15,8 @@ import { IDelegationManager } from "../../src/interfaces/IDelegationManager.sol" import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// Events ////////////////////////////// event IncreasedCount( address indexed sender, address indexed redeemer, bytes32 indexed delegationHash, uint256 limit, uint256 callCount @@ -21,6 +25,7 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { ////////////////////// State ////////////////////// LimitedCallsEnforcer public limitedCallsEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -34,9 +39,14 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { // should SUCCEED to INVOKE method BELOW limit number function test_methodCanBeCalledBelowLimitNumber() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint256 transactionsLimit_ = 1; bytes memory inputTerms_ = abi.encodePacked(transactionsLimit_); Caveat[] memory caveats_ = new Caveat[](1); @@ -55,7 +65,7 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectEmit(true, true, true, true, address(limitedCallsEnforcer)); emit IncreasedCount(address(delegationManager), address(0), delegationHash_, 1, 1); - limitedCallsEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + limitedCallsEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0)); assertEq(limitedCallsEnforcer.callCounts(address(delegationManager), delegationHash_), transactionsLimit_); } @@ -64,9 +74,14 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { // should FAIL to INVOKE method ABOVE limit number function test_methodFailsIfCalledAboveLimitNumber() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint256 transactionsLimit_ = 1; bytes memory inputTerms_ = abi.encodePacked(transactionsLimit_); Caveat[] memory caveats_ = new Caveat[](1); @@ -83,22 +98,24 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { bytes32 delegationHash_ = EncoderLib._getDelegationHash(delegation_); assertEq(limitedCallsEnforcer.callCounts(address(delegationManager), delegationHash_), 0); vm.startPrank(address(delegationManager)); - limitedCallsEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + limitedCallsEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0)); vm.expectRevert("LimitedCallsEnforcer:limit-exceeded"); - limitedCallsEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + limitedCallsEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0)); assertEq(limitedCallsEnforcer.callCounts(address(delegationManager), delegationHash_), transactionsLimit_); } // should FAIL to INVOKE with invalid input terms function test_methodFailsIfCalledWithInvalidInputTerms() public { - Action memory action_; + Execution memory execution_; + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory terms_ = abi.encodePacked(uint32(1)); vm.expectRevert("LimitedCallsEnforcer:invalid-terms-length"); - limitedCallsEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), address(0), address(0)); + limitedCallsEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), address(0), address(0)); terms_ = abi.encodePacked(uint256(1), uint256(1)); vm.expectRevert("LimitedCallsEnforcer:invalid-terms-length"); - limitedCallsEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), address(0), address(0)); + limitedCallsEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), address(0), address(0)); } ////////////////////// Integration ////////////////////// @@ -107,9 +124,12 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { function test_methodFailsAboveLimitIntegration() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); bytes memory inputTerms_ = abi.encodePacked(uint256(1)); Caveat[] memory caveats_ = new Caveat[](1); caveats_[0] = Caveat({ args: hex"", enforcer: address(limitedCallsEnforcer), terms: inputTerms_ }); @@ -132,13 +152,13 @@ contract LimitedCallsEnforcerTest is CaveatEnforcerBaseTest { Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has increased by 1 uint256 valueAfter_ = aliceDeleGatorCounter.count(); assertEq(valueAfter_, initialValue_ + 1); - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has not increased assertEq(aliceDeleGatorCounter.count(), valueAfter_); diff --git a/test/enforcers/NativeAllowanceEnforcer.t.sol b/test/enforcers/NativeAllowanceEnforcer.t.sol index ee5a903..8cc5e47 100644 --- a/test/enforcers/NativeAllowanceEnforcer.t.sol +++ b/test/enforcers/NativeAllowanceEnforcer.t.sol @@ -1,13 +1,21 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { NativeTokenTransferAmountEnforcer } from "../../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + + ////////////////////// State ////////////////////// + ModeCode mode = ModeLib.encodeSimpleSingle(); + ////////////////////// Set up ////////////////////// NativeTokenTransferAmountEnforcer public nativeTokenTransferAmountEnforcer; @@ -29,8 +37,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { function test_transferSucceedsIfCalledBelowAllowance() public { uint256 allowance_ = 1 ether; - // Create the action that would be executed - Action memory action_ = Action({ to: address(users.bob.deleGator), value: 1 ether, data: hex"" }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ target: address(users.bob.deleGator), value: 1 ether, callData: hex"" }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory inputTerms_ = abi.encode(allowance_); @@ -42,7 +51,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( address(delegationManager), address(0), delegationHash_, allowance_, 1 ether ); - nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + nativeTokenTransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), allowance_); } @@ -51,8 +62,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { function test_transferSucceedsIfCalledBelowAllowanceMultipleCalls() public { uint256 allowance_ = 3 ether; - // Create the action that would be executed - Action memory action_ = Action({ to: address(users.bob.deleGator), value: 1 ether, data: hex"" }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ target: address(users.bob.deleGator), value: 1 ether, callData: hex"" }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory inputTerms_ = abi.encode(allowance_); @@ -65,7 +77,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( address(delegationManager), address(0), delegationHash_, allowance_, 1 ether ); - nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + nativeTokenTransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 1 ether); // Second use @@ -73,7 +87,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( address(delegationManager), address(0), delegationHash_, allowance_, 2 ether ); - nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + nativeTokenTransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 2 ether); // Third use, maximum allowance used @@ -81,7 +97,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { emit NativeTokenTransferAmountEnforcer.IncreasedSpentMap( address(delegationManager), address(0), delegationHash_, allowance_, allowance_ ); - nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + nativeTokenTransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), allowance_); } @@ -91,9 +109,10 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { function test_transferFailsIfAllowanceExceeded() public { uint256 allowance_ = 1 ether; - // Create the action that would be executed + // Create the execution that would be executed // The value is higher than the allowance - Action memory action_ = Action({ to: address(users.bob.deleGator), value: allowance_ + 1, data: hex"" }); + Execution memory execution_ = Execution({ target: address(users.bob.deleGator), value: allowance_ + 1, callData: hex"" }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory inputTerms_ = abi.encode(allowance_); @@ -102,7 +121,9 @@ contract NativeAllowanceEnforcerTest is CaveatEnforcerBaseTest { assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); vm.prank(address(delegationManager)); vm.expectRevert("NativeTokenTransferAmountEnforcer:allowance-exceeded"); - nativeTokenTransferAmountEnforcer.beforeHook(inputTerms_, hex"", action_, delegationHash_, address(0), address(0)); + nativeTokenTransferAmountEnforcer.beforeHook( + inputTerms_, hex"", mode, executionCallData_, delegationHash_, address(0), address(0) + ); // The allowance does not change assertEq(nativeTokenTransferAmountEnforcer.spentMap(address(delegationManager), delegationHash_), 0); diff --git a/test/enforcers/NativeBalanceGteEnforcer.t.sol b/test/enforcers/NativeBalanceGteEnforcer.t.sol index e14b151..afaaf3a 100644 --- a/test/enforcers/NativeBalanceGteEnforcer.t.sol +++ b/test/enforcers/NativeBalanceGteEnforcer.t.sol @@ -1,20 +1,26 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; + import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { NativeBalanceGteEnforcer } from "../../src/enforcers/NativeBalanceGteEnforcer.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; import { Counter } from "../utils/Counter.t.sol"; contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// NativeBalanceGteEnforcer public enforcer; address delegator; address delegate; address dm; - Action noAction; + Execution noExecution; + bytes executionCallData = abi.encode(noExecution); + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -25,7 +31,7 @@ contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { dm = address(delegationManager); enforcer = new NativeBalanceGteEnforcer(); vm.label(address(enforcer), "NativeBalanceGte Enforcer"); - noAction = Action(address(0), 0, hex""); + noExecution = Execution(address(0), 0, hex""); } ////////////////////// Basic Functionality ////////////////////// @@ -48,14 +54,14 @@ contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase by 100 vm.startPrank(dm); - enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); _increaseBalance(delegator, 100); - enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); // Increase by 1000 - enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); _increaseBalance(delegator, 1000); - enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); } // ////////////////////// Errors ////////////////////// @@ -68,10 +74,10 @@ contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase by 10, expect revert vm.startPrank(dm); - enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); _increaseBalance(delegator, 10); vm.expectRevert(bytes("NativeBalanceGteEnforcer:balance-not-gt")); - enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); } // Reverts if a enforcer is locked @@ -84,19 +90,19 @@ contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { // Increase by 100 vm.startPrank(dm); // Locks the enforcer - enforcer.beforeHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, delegationHash_, delegator, delegate); bytes32 hashKey_ = enforcer.getHashKey(address(delegationManager), delegationHash_); assertTrue(enforcer.isLocked(hashKey_)); vm.expectRevert(bytes("NativeBalanceGteEnforcer:enforcer-is-locked")); - enforcer.beforeHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, delegationHash_, delegator, delegate); _increaseBalance(delegator, 1000); vm.startPrank(dm); // Unlocks the enforcer - enforcer.afterHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, executionCallData, delegationHash_, delegator, delegate); assertFalse(enforcer.isLocked(hashKey_)); // Can be used again, and locks it again - enforcer.beforeHook(terms_, hex"", noAction, delegationHash_, delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, delegationHash_, delegator, delegate); assertTrue(enforcer.isLocked(hashKey_)); } @@ -124,9 +130,9 @@ contract NativeBalanceGteEnforcerTest is CaveatEnforcerBaseTest { bytes memory terms_ = abi.encodePacked(recipient_, type(uint256).max); vm.deal(recipient_, type(uint256).max); vm.startPrank(dm); - enforcer.beforeHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); vm.expectRevert(); - enforcer.afterHook(terms_, hex"", noAction, bytes32(0), delegator, delegate); + enforcer.afterHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, delegate); } function _increaseBalance(address _recipient, uint256 _amount) internal { diff --git a/test/enforcers/NativeTokenPaymentEnforcer.t.sol b/test/enforcers/NativeTokenPaymentEnforcer.t.sol index 0fd3458..94fbb96 100644 --- a/test/enforcers/NativeTokenPaymentEnforcer.t.sol +++ b/test/enforcers/NativeTokenPaymentEnforcer.t.sol @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { NativeTokenPaymentEnforcer } from "../../src/enforcers/NativeTokenPaymentEnforcer.sol"; import { NativeTokenTransferAmountEnforcer } from "../../src/enforcers/NativeTokenTransferAmountEnforcer.sol"; @@ -14,6 +17,8 @@ import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; import { Counter } from "../utils/Counter.t.sol"; contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////// Set up ////////////////////// NativeTokenPaymentEnforcer public nativeTokenPaymentEnforcer; NativeTokenTransferAmountEnforcer public nativeTokenTransferAmountEnforcer; @@ -70,8 +75,13 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { (bytes32 delegationHash_,) = _getExampleDelegation(terms_, hex""); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + ModeCode mode_ = ModeLib.encodeSimpleSingle(); vm.startPrank(address(delegationManager)); vm.expectEmit(true, true, true, true, address(nativeTokenPaymentEnforcer)); @@ -79,7 +89,9 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { address(delegationManager), delegationHash_, recipient_, address(users.alice.deleGator), address(0), 1 ether ); - nativeTokenPaymentEnforcer.afterHook(terms_, args_, action_, delegationHash_, address(users.alice.deleGator), address(0)); + nativeTokenPaymentEnforcer.afterHook( + terms_, args_, mode_, executionCallData_, delegationHash_, address(users.alice.deleGator), address(0) + ); } // Should SUCCEED to make the payment with a redelegation @@ -114,8 +126,13 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { (bytes32 delegationHash_,) = _getExampleDelegation(terms_, hex""); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + ModeCode mode_ = ModeLib.encodeSimpleSingle(); vm.startPrank(address(delegationManager)); vm.expectEmit(true, true, true, true, address(nativeTokenPaymentEnforcer)); @@ -123,14 +140,15 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { address(delegationManager), delegationHash_, recipient_, address(users.alice.deleGator), address(0), 1 ether ); - nativeTokenPaymentEnforcer.afterHook(terms_, args_, action_, delegationHash_, address(users.alice.deleGator), address(0)); + nativeTokenPaymentEnforcer.afterHook( + terms_, args_, mode_, executionCallData_, delegationHash_, address(users.alice.deleGator), address(0) + ); } // Should only overwrite the args of the args equality enforcer function test_onlyOverwriteAllowanceEnforcerArgs() public { // The terms indicate to send 1 ether to Alice. - address recipient_ = address(users.alice.deleGator); - bytes memory paymentTerms_ = abi.encodePacked(recipient_, uint256(1 ether)); + bytes memory paymentTerms_ = abi.encodePacked(address(users.alice.deleGator), uint256(1 ether)); (bytes32 delegationHash_, Delegation memory paidDelegation_) = _getExampleDelegation(paymentTerms_, hex""); Delegation[] memory paidDelegations_ = new Delegation[](1); @@ -146,7 +164,11 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { Caveat[] memory paymentCaveats_ = new Caveat[](4); paymentCaveats_[0] = Caveat({ args: hex"", enforcer: address(nativeTokenTransferAmountEnforcer), terms: allowanceTerms_ }); paymentCaveats_[1] = Caveat({ args: hex"", enforcer: address(limitedCallsEnforcer), terms: abi.encodePacked(uint256(10)) }); - paymentCaveats_[2] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(recipient_) }); + paymentCaveats_[2] = Caveat({ + args: hex"", + enforcer: address(allowedTargetsEnforcer), + terms: abi.encodePacked(address(users.alice.deleGator)) + }); paymentCaveats_[3] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsTerms_ }); // Create payment delegation from Bob to NativeTokenPaymentEnforcer @@ -165,8 +187,11 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // The args contain the payment delegation to redeem bytes memory args_ = abi.encode(paymentDelegations_); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); vm.startPrank(address(delegationManager)); @@ -179,7 +204,13 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { paymentDelegations_[0].delegator, address(nativeTokenPaymentEnforcer), paymentDelegations_[0] ); nativeTokenPaymentEnforcer.afterHook( - paymentTerms_, args_, action_, delegationHash_, address(users.alice.deleGator), address(0) + paymentTerms_, + args_, + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData), + delegationHash_, + address(users.alice.deleGator), + address(0) ); } @@ -208,7 +239,6 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { salt: 0, signature: hex"" }); - paymentDelegations_[0] = signDelegation(users.bob, paymentDelegations_[0]); // Using a mock delegation manager @@ -219,12 +249,17 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { (bytes32 delegationHash_,) = _getExampleDelegation(terms_, hex""); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + ModeCode mode_ = ModeLib.encodeSimpleSingle(); vm.startPrank(mockDelegationManager_); vm.expectRevert("NativeTokenPaymentEnforcer:payment-not-received"); - nativeTokenPaymentEnforcer.afterHook(terms_, args_, action_, delegationHash_, address(0), address(0)); + nativeTokenPaymentEnforcer.afterHook(terms_, args_, mode_, executionCallData_, delegationHash_, address(0), address(0)); } // Should FAIL if the sender is different from the delegation manager. @@ -232,7 +267,9 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // Using an invalid sender, it must be the delegation manager vm.startPrank(address(users.bob.deleGator)); vm.expectRevert("NativeTokenPaymentEnforcer:only-delegation-manager"); - nativeTokenPaymentEnforcer.afterHook(hex"", hex"", new Action[](1)[0], bytes32(0), address(0), address(0)); + nativeTokenPaymentEnforcer.afterHook( + hex"", hex"", ModeLib.encodeSimpleSingle(), new bytes(0), bytes32(0), address(0), address(0) + ); } function test_chargePaymentFromAllowance() public { @@ -269,8 +306,11 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // The args contain the payment delegation to redeem bytes memory args_ = abi.encode(paymentDelegations_); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); uint256 aliceBalanceBefore_ = address(users.alice.deleGator).balance; @@ -278,7 +318,7 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // Pass the delegation payment in the args. paidDelegations_[0].caveats[0].args = args_; - invokeDelegation_UserOp(users.bob, paidDelegations_, action_); + invokeDelegation_UserOp(users.bob, paidDelegations_, execution_); assertEq(aliceDeleGatorCounter.count(), 1); @@ -324,8 +364,11 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // The args contain the payment delegation to redeem bytes memory argsWithBobPayment_ = abi.encode(paymentDelegations_); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); uint256 aliceBalanceBefore_ = address(users.alice.deleGator).balance; @@ -333,7 +376,7 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // Pass the delegation payment in the args. maliciousPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; - invokeDelegation_UserOp(users.carol, maliciousPaidDelegations_, action_); + invokeDelegation_UserOp(users.carol, maliciousPaidDelegations_, execution_); assertEq(aliceDeleGatorCounter.count(), 1); // Alice received the payment @@ -341,7 +384,7 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // Pass the delegation payment in the args. originalPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; - invokeDelegation_UserOp(users.bob, originalPaidDelegations_, action_); + invokeDelegation_UserOp(users.bob, originalPaidDelegations_, execution_); // The execution did not work because the allowance has already been used. assertEq(aliceDeleGatorCounter.count(), 1); } @@ -389,8 +432,11 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // The args contain the payment delegation to redeem bytes memory argsWithBobPayment_ = abi.encode(paymentDelegations_); - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); uint256 aliceBalanceBefore_ = address(users.alice.deleGator).balance; @@ -398,7 +444,7 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // Pass the delegation payment in the args. maliciousPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; - invokeDelegation_UserOp(users.carol, maliciousPaidDelegations_, action_); + invokeDelegation_UserOp(users.carol, maliciousPaidDelegations_, execution_); // The execution did not work because the allowance fails due to the invalid args. assertEq(aliceDeleGatorCounter.count(), 0); // Alice did not receive the payment @@ -406,7 +452,7 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { // Pass the delegation payment in the args. originalPaidDelegations_[0].caveats[0].args = argsWithBobPayment_; - invokeDelegation_UserOp(users.bob, originalPaidDelegations_, action_); + invokeDelegation_UserOp(users.bob, originalPaidDelegations_, execution_); // The execution works well with a proper args assertEq(aliceDeleGatorCounter.count(), 1); // Alice received the payment @@ -464,9 +510,15 @@ contract NativeTokenPaymentEnforcerTest is CaveatEnforcerBaseTest { } } -/// @dev This contract is used for testing a case where the redeemDelegation() function doesn't work as expected +/// @dev This contract is used for testing a case where the redeemDelegations() function doesn't work as expected contract MockDelegationManager { - function redeemDelegation(bytes[] calldata _permissionContexts, Action[] calldata _actions) external { - // Does not do anything, the action is not processed + function redeemDelegations( + bytes[] calldata _permissionContexts, + ModeCode[] calldata _modes, + bytes[] calldata _executionCallDatas + ) + external + { + // Does not do anything, the execution is not processed } } diff --git a/test/enforcers/NonceEnforcer.t.sol b/test/enforcers/NonceEnforcer.t.sol index 2658db2..3252eb1 100644 --- a/test/enforcers/NonceEnforcer.t.sol +++ b/test/enforcers/NonceEnforcer.t.sol @@ -2,19 +2,25 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { NonceEnforcer } from "../../src/enforcers/NonceEnforcer.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract NonceEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// NonceEnforcer public enforcer; - Action action = Action({ to: address(0), value: 0, data: hex"" }); + Execution execution = Execution({ target: address(0), value: 0, callData: hex"" }); + bytes executionCallData = ExecutionLib.encodeSingle(execution.target, execution.value, execution.callData); address delegator = address(users.alice.deleGator); address dm = address(delegationManager); + ModeCode mode = ModeLib.encodeSimpleSingle(); ////////////////////////////// Events ////////////////////////////// @@ -66,7 +72,7 @@ contract NonceEnforcerTest is CaveatEnforcerBaseTest { vm.startPrank(dm); // Should not revert - enforcer.beforeHook(terms_, hex"", action, bytes32(0), delegator, address(0)); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, address(0)); } ////////////////////// Errors ////////////////////// @@ -94,7 +100,7 @@ contract NonceEnforcerTest is CaveatEnforcerBaseTest { bytes memory terms_ = abi.encode(nonce_ + 1); vm.startPrank(dm); vm.expectRevert(bytes("NonceEnforcer:invalid-nonce")); - enforcer.beforeHook(terms_, hex"", action, bytes32(0), delegator, address(0)); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, address(0)); // Increment ID so the current ID is high enough to check a lower ID vm.startPrank(dm); @@ -105,7 +111,7 @@ contract NonceEnforcerTest is CaveatEnforcerBaseTest { terms_ = abi.encode(nonce_ - 1); vm.startPrank(dm); vm.expectRevert(bytes("NonceEnforcer:invalid-nonce")); - enforcer.beforeHook(terms_, hex"", action, bytes32(0), delegator, address(0)); + enforcer.beforeHook(terms_, hex"", mode, executionCallData, bytes32(0), delegator, address(0)); } ////////////////////// Integration ////////////////////// diff --git a/test/enforcers/PasswordEnforcer.t.sol b/test/enforcers/PasswordEnforcer.t.sol index 91569c2..15ca38d 100644 --- a/test/enforcers/PasswordEnforcer.t.sol +++ b/test/enforcers/PasswordEnforcer.t.sol @@ -2,9 +2,11 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { PasswordEnforcer } from "../utils/PasswordCaveatEnforcer.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; @@ -15,8 +17,11 @@ import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/Mes import { SigningUtilsLib } from "../utils/SigningUtilsLib.t.sol"; contract PasswordEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// PasswordEnforcer public passwordEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -27,7 +32,8 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { } function test_userInputCorrectArgsWorks() public { - Action memory action_; + Execution memory execution_; + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); uint256 password_ = uint256(123456789); bytes memory terms_ = abi.encode(password_); address delegator_ = address(users.alice.deleGator); @@ -35,11 +41,12 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { vm.startPrank(address(delegationManager)); // First usage works well - passwordEnforcer.beforeHook(terms_, abi.encode(password_), action_, bytes32(0), delegator_, address(0)); + passwordEnforcer.beforeHook(terms_, abi.encode(password_), mode, executionCallData_, bytes32(0), delegator_, address(0)); } function test_userInputIncorrectArgs() public { - Action memory action_; + Execution memory execution_; + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); uint256 password_ = uint256(123456789); uint256 incorrectPassword_ = uint256(5154848789); bytes memory terms_ = abi.encode(password_); @@ -49,16 +56,21 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { vm.expectRevert("PasswordEnforcerError"); - passwordEnforcer.beforeHook(terms_, abi.encode(incorrectPassword_), action_, bytes32(0), delegator_, address(0)); + passwordEnforcer.beforeHook( + terms_, abi.encode(incorrectPassword_), mode, executionCallData_, bytes32(0), delegator_, address(0) + ); } ////////////////////// Integration ////////////////////// function test_userInputIncorrectArgsWithOffchainDelegation() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); bytes memory inputTerms_ = abi.encode(uint256(12345)); bytes memory incorrectPassword_ = abi.encode(uint256(123154245)); @@ -81,7 +93,7 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has not increased assertEq(aliceDeleGatorCounter.count(), initialValue_); } @@ -90,9 +102,12 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { function test_userInputCorrectArgsWorksWithOffchainDelegation() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); bytes memory inputTerms_ = abi.encode(uint256(12345)); bytes memory password_ = abi.encode(uint256(12345)); @@ -122,16 +137,19 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has increased by 1 assertEq(aliceDeleGatorCounter.count(), initialValue_ + 1); } function test_userInputIncorrectArgsWorksWithOffchainDelegation() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); bytes memory inputTerms_ = abi.encode(uint256(12345)); @@ -162,7 +180,7 @@ contract PasswordEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Validate that the count has NOT increased assertEq(aliceDeleGatorCounter.count(), initialValue_); } diff --git a/test/enforcers/RedeemerEnforcer.t.sol b/test/enforcers/RedeemerEnforcer.t.sol index 396c8eb..6ac8030 100644 --- a/test/enforcers/RedeemerEnforcer.t.sol +++ b/test/enforcers/RedeemerEnforcer.t.sol @@ -1,15 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.23; -import { Action } from "../../src/utils/Types.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; + +import { Execution, ModeCode } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { RedeemerEnforcer } from "../../src/enforcers/RedeemerEnforcer.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract RedeemerEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// RedeemerEnforcer public redeemerEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -31,23 +37,37 @@ contract RedeemerEnforcerTest is CaveatEnforcerBaseTest { // should pass if called from a single valid redeemer function test_validSingleRedeemerCanExecute() public { - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory terms_ = abi.encodePacked(address(users.bob.deleGator)); vm.prank(address(delegationManager)); - redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.bob.deleGator)); + redeemerEnforcer.beforeHook( + terms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(users.bob.deleGator) + ); } // should pass if called from multiple valid redeemers function test_validMultipleRedeemersCanExecute() public { - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory terms_ = abi.encodePacked(address(users.alice.deleGator), address(users.bob.deleGator)); vm.startPrank(address(delegationManager)); - redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.alice.deleGator)); - redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.bob.deleGator)); + redeemerEnforcer.beforeHook( + terms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(users.alice.deleGator) + ); + redeemerEnforcer.beforeHook( + terms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(users.bob.deleGator) + ); } ////////////////////// Invalid cases ////////////////////// @@ -60,25 +80,37 @@ contract RedeemerEnforcerTest is CaveatEnforcerBaseTest { // should revert if called from an invalid redeemer function test_revertWithInvalidRedeemer() public { - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory terms_ = abi.encodePacked(address(users.bob.deleGator)); vm.prank(address(delegationManager)); // Dave is not a valid redeemer vm.expectRevert("RedeemerEnforcer:unauthorized-redeemer"); - redeemerEnforcer.beforeHook(terms_, hex"", action_, keccak256(""), address(0), address(users.dave.deleGator)); + redeemerEnforcer.beforeHook( + terms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(users.dave.deleGator) + ); } // should revert with invalid terms length function test_revertWithInvalidTerms() public { - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); bytes memory invalidTerms_ = abi.encodePacked(uint8(1)); vm.prank(address(delegationManager)); vm.expectRevert("RedeemerEnforcer:invalid-terms-length"); - redeemerEnforcer.beforeHook(invalidTerms_, hex"", action_, keccak256(""), address(0), address(users.bob.deleGator)); + redeemerEnforcer.beforeHook( + invalidTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(users.bob.deleGator) + ); } function _getEnforcer() internal view override returns (ICaveatEnforcer) { diff --git a/test/enforcers/TimestampEnforcer.t.sol b/test/enforcers/TimestampEnforcer.t.sol index 2d6b2d6..1accd25 100644 --- a/test/enforcers/TimestampEnforcer.t.sol +++ b/test/enforcers/TimestampEnforcer.t.sol @@ -2,8 +2,10 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -import { Action, Caveat, Delegation } from "../../src/utils/Types.sol"; +import { Execution, Caveat, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { Counter } from "../utils/Counter.t.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { TimestampEnforcer } from "../../src/enforcers/TimestampEnforcer.sol"; @@ -13,9 +15,12 @@ import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract TimestampEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////// State ////////////////////// TimestampEnforcer public timestampEnforcer; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////// Set up ////////////////////// @@ -29,49 +34,68 @@ contract TimestampEnforcerTest is CaveatEnforcerBaseTest { // should SUCCEED to INVOKE method AFTER timestamp reached function test_methodCanBeCalledAfterTimestamp() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + skip(1 hours); // Increase time 1 hour uint128 timestampAfterThreshold_ = 1; // Minimum timestamp uint128 timestampBeforeThreshold_ = 0; // Not using before threshold bytes memory inputTerms_ = abi.encodePacked(timestampAfterThreshold_, timestampBeforeThreshold_); vm.prank(address(delegationManager)); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should SUCCEED to INVOKE method BEFORE timestamp reached function test_methodCanBeCalledBeforeTimestamp() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 timestampAfterThreshold_ = 0; // Not using after threshold uint128 timestampBeforeThreshold_ = uint128(block.timestamp + 1 hours); bytes memory inputTerms_ = abi.encodePacked(timestampAfterThreshold_, timestampBeforeThreshold_); vm.prank(address(delegationManager)); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should SUCCEED to INVOKE method inside of timestamp RANGE function test_methodCanBeCalledInsideTimestampRange() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 timestampAfterThreshold_ = 1; // Minimum timestamp uint128 timestampBeforeThreshold_ = uint128(block.timestamp + 1 hours); skip(1 minutes); // Increase time 1 minute bytes memory inputTerms_ = abi.encodePacked(timestampAfterThreshold_, timestampBeforeThreshold_); vm.prank(address(delegationManager)); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } ////////////////////// Invalid cases ////////////////////// // should FAIL to INVOKE method BEFORE timestamp reached function test_methodFailsIfCalledTimestamp() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); uint128 timestampAfterThreshold_ = uint128(block.timestamp + 1 hours); uint128 timestampBeforeThreshold_ = 0; // Not using before threshold @@ -79,69 +103,89 @@ contract TimestampEnforcerTest is CaveatEnforcerBaseTest { vm.prank(address(delegationManager)); vm.expectRevert("TimestampEnforcer:early-delegation"); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE method AFTER timestamp reached function test_methodFailsIfCalledAfterTimestamp() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 timestampAfterThreshold_ = 0; // Not using after threshold uint128 timestampBeforeThreshold_ = uint128(block.timestamp); skip(1 hours); // Increase time 1 hour bytes memory inputTerms_ = abi.encodePacked(timestampAfterThreshold_, timestampBeforeThreshold_); vm.prank(address(delegationManager)); vm.expectRevert("TimestampEnforcer:expired-delegation"); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE method BEFORE timestamp RANGE function test_methodFailsIfCalledBeforeTimestampRange() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 timestampAfterThreshold_ = uint128(block.timestamp + 1 hours); uint128 timestampBeforeThreshold_ = uint128(block.timestamp + 2 hours); bytes memory inputTerms_ = abi.encodePacked(timestampAfterThreshold_, timestampBeforeThreshold_); vm.prank(address(delegationManager)); vm.expectRevert("TimestampEnforcer:early-delegation"); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE method AFTER timestamp RANGE function test_methodFailsIfCalledAfterTimestampRange() public { - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + uint128 timestampAfterThreshold_ = uint128(block.timestamp + 1 hours); uint128 timestampBeforeThreshold_ = uint128(block.timestamp + 2 hours); skip(3 hours); // Increase time 3 hours bytes memory inputTerms_ = abi.encodePacked(timestampAfterThreshold_, timestampBeforeThreshold_); vm.prank(address(delegationManager)); vm.expectRevert("TimestampEnforcer:expired-delegation"); - timestampEnforcer.beforeHook(inputTerms_, hex"", action_, keccak256(""), address(0), address(0)); + timestampEnforcer.beforeHook(inputTerms_, hex"", mode, executionCallData_, keccak256(""), address(0), address(0)); } // should FAIL to INVOKE with invalid input terms function test_methodFailsIfCalledWithInvalidInputTerms() public { - Action memory action_; + Execution memory execution_; + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); + bytes memory terms_ = abi.encodePacked(uint32(1)); vm.expectRevert("TimestampEnforcer:invalid-terms-length"); - timestampEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), address(0), address(0)); + timestampEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), address(0), address(0)); terms_ = abi.encodePacked(uint256(1), uint256(1)); vm.expectRevert("TimestampEnforcer:invalid-terms-length"); - timestampEnforcer.beforeHook(terms_, hex"", action_, bytes32(0), address(0), address(0)); + timestampEnforcer.beforeHook(terms_, hex"", mode, executionCallData_, bytes32(0), address(0), address(0)); } ////////////////////// Integration ////////////////////// // should SUCCEED to INVOKE until reaching timestamp Integration function test_methodCanBeCalledAfterTimestampIntegration() public { uint256 initialValue_ = aliceDeleGatorCounter.count(); - // Create the action that would be executed - Action memory action_ = - Action({ to: address(aliceDeleGatorCounter), value: 0, data: abi.encodeWithSelector(Counter.increment.selector) }); + // Create the execution that would be executed + Execution memory execution_ = Execution({ + target: address(aliceDeleGatorCounter), + value: 0, + callData: abi.encodeWithSelector(Counter.increment.selector) + }); skip(10); // Increase time 10 seconds // Not using before threshold (timestampAfterThreshold_ = 1, timestampBeforeThreshold_ = 100) bytes memory inputTerms_ = abi.encodePacked(uint128(1), uint128(100)); @@ -164,7 +208,7 @@ contract TimestampEnforcerTest is CaveatEnforcerBaseTest { delegations_[0] = delegation; // Enforcer allows the delegation - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 valueAfter_ = aliceDeleGatorCounter.count(); @@ -174,7 +218,7 @@ contract TimestampEnforcerTest is CaveatEnforcerBaseTest { // Enforcer blocks the delegation skip(100); // Increase time 100 seconds - invokeDelegation_UserOp(users.bob, delegations_, action_); + invokeDelegation_UserOp(users.bob, delegations_, execution_); // Get final count uint256 finalValue_ = aliceDeleGatorCounter.count(); // Validate that the count has not increased by 1 diff --git a/test/enforcers/ValueLteEnforcer.t.sol b/test/enforcers/ValueLteEnforcer.t.sol index 6adf975..737b61b 100644 --- a/test/enforcers/ValueLteEnforcer.t.sol +++ b/test/enforcers/ValueLteEnforcer.t.sol @@ -3,18 +3,23 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; import { BasicERC20 } from "../utils/BasicERC20.t.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; import "../../src/utils/Types.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution, ModeCode } from "../../src/utils/Types.sol"; import { CaveatEnforcerBaseTest } from "./CaveatEnforcerBaseTest.t.sol"; import { ValueLteEnforcer } from "../../src/enforcers/ValueLteEnforcer.sol"; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; contract ValueLteEnforcerTest is CaveatEnforcerBaseTest { + using ModeLib for ModeCode; + ////////////////////////////// State ////////////////////////////// ValueLteEnforcer public enforcer; BasicERC20 public token; address delegator; + ModeCode public mode = ModeLib.encodeSimpleSingle(); ////////////////////////////// Events ////////////////////////////// @@ -53,25 +58,27 @@ contract ValueLteEnforcerTest is CaveatEnforcerBaseTest { // Validates that valid values don't revert function test_allow_valueLte() public view { // Equal - bytes memory terms_ = abi.encodePacked(uint256(1 ether)); - Action memory action_ = Action({ - to: address(users.alice.deleGator), + bytes memory terms_ = abi.encode(uint256(1 ether)); + Execution memory execution_ = Execution({ + target: address(users.alice.deleGator), value: 1 ether, - data: abi.encodeWithSignature("test_valueLteIsAllowed()") + callData: abi.encodeWithSignature("test_valueLteIsAllowed()") }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Should not revert - enforcer.beforeHook(terms_, "", action_, bytes32(0), address(0), address(0)); + enforcer.beforeHook(terms_, "", mode, executionCallData_, bytes32(0), address(0), address(0)); // Less than - action_ = Action({ - to: address(users.alice.deleGator), + execution_ = Execution({ + target: address(users.alice.deleGator), value: 0.1 ether, - data: abi.encodeWithSignature("test_valueLteIsAllowed()") + callData: abi.encodeWithSignature("test_valueLteIsAllowed()") }); + executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Should not revert - enforcer.beforeHook(terms_, "", action_, bytes32(0), address(0), address(0)); + enforcer.beforeHook(terms_, "", mode, executionCallData_, bytes32(0), address(0), address(0)); } //////////////////////// Errors //////////////////////// @@ -80,15 +87,16 @@ contract ValueLteEnforcerTest is CaveatEnforcerBaseTest { function test_notAllow_valueGt() public { // Gt bytes memory terms_ = abi.encodePacked(uint256(1 ether)); - Action memory action_ = Action({ - to: address(users.alice.deleGator), + Execution memory execution_ = Execution({ + target: address(users.alice.deleGator), value: 2 ether, - data: abi.encodeWithSignature("test_valueLteIsAllowed()") + callData: abi.encodeWithSignature("test_valueLteIsAllowed()") }); + bytes memory executionCallData_ = ExecutionLib.encodeSingle(execution_.target, execution_.value, execution_.callData); // Should not revert vm.expectRevert(bytes("ValueLteEnforcer:value-too-high")); - enforcer.beforeHook(terms_, "", action_, bytes32(0), address(0), address(0)); + enforcer.beforeHook(terms_, "", mode, executionCallData_, bytes32(0), address(0), address(0)); } // Validates the terms are well formed diff --git a/test/metaTests/EncoderLibTest.t.sol b/test/metaTests/EncoderLibTest.t.sol index e188e95..530ca89 100644 --- a/test/metaTests/EncoderLibTest.t.sol +++ b/test/metaTests/EncoderLibTest.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.23; import { Test } from "forge-std/Test.sol"; import { Caveat, Delegation } from "../../src/utils/Types.sol"; -import { DELEGATION_TYPEHASH, CAVEAT_TYPEHASH } from "../../src/utils/Typehashes.sol"; +import { DELEGATION_TYPEHASH, CAVEAT_TYPEHASH } from "../../src/utils/Constants.sol"; import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; contract EncoderLibTest is Test { diff --git a/test/metaTests/TypehashTest.t.sol b/test/metaTests/TypehashTest.t.sol index 8d8d066..d999d14 100644 --- a/test/metaTests/TypehashTest.t.sol +++ b/test/metaTests/TypehashTest.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import "forge-std/Test.sol"; -import { EIP712_DOMAIN_TYPEHASH, DELEGATION_TYPEHASH, CAVEAT_TYPEHASH } from "../../src/utils/Typehashes.sol"; +import { EIP712_DOMAIN_TYPEHASH, DELEGATION_TYPEHASH, CAVEAT_TYPEHASH } from "../../src/utils/Constants.sol"; contract TypehashTest is Test { ////////////////////////////// State ////////////////////////////// diff --git a/test/utils/BaseTest.t.sol b/test/utils/BaseTest.t.sol index e27fd9f..e5e6301 100644 --- a/test/utils/BaseTest.t.sol +++ b/test/utils/BaseTest.t.sol @@ -9,23 +9,26 @@ import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy import { FCL_ecdsa_utils } from "@freshCryptoLib/FCL_ecdsa_utils.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { IEntryPoint } from "@account-abstraction/core/EntryPoint.sol"; +import { ModeLib } from "@erc7579/lib/ModeLib.sol"; +import { ExecutionLib } from "@erc7579/lib/ExecutionLib.sol"; -// import { P256 } from "../../src/external/Daimo/P256.sol"; import { P256FCLVerifierLib } from "../../src/libraries/P256FCLVerifierLib.sol"; import { FCL_all_wrapper } from "./FCLWrapperLib.sol"; +import { EXECUTE_SIGNATURE } from "./Constants.sol"; import { EncoderLib } from "../../src/libraries/EncoderLib.sol"; import { TestUser, TestUsers, Implementation, SignatureType } from "./Types.t.sol"; import { SigningUtilsLib } from "./SigningUtilsLib.t.sol"; import { StorageUtilsLib } from "./StorageUtilsLib.t.sol"; -import { Action, PackedUserOperation, Delegation } from "../../src/utils/Types.sol"; +import { Execution, PackedUserOperation, Delegation, ModeCode } from "../../src/utils/Types.sol"; import { SimpleFactory } from "../../src/utils/SimpleFactory.sol"; import { DelegationManager } from "../../src/DelegationManager.sol"; -import { IDeleGatorCoreFull } from "../../src/interfaces/IDeleGatorCoreFull.sol"; +import { DeleGatorCore } from "../../src/DeleGatorCore.sol"; import { HybridDeleGator } from "../../src/HybridDeleGator.sol"; import { MultiSigDeleGator } from "../../src/MultiSigDeleGator.sol"; abstract contract BaseTest is Test { + using ModeLib for ModeCode; using MessageHashUtils for bytes32; SignatureType public SIGNATURE_TYPE; @@ -273,23 +276,27 @@ abstract contract BaseTest is Test { userOperation_ = createAndSignUserOp(_user, _sender, _callData, hex""); } - function execute_UserOp(TestUser memory _user, Action memory _action) public { - execute_UserOp(_user, _action, false); + function execute_UserOp(TestUser memory _user, Execution memory _execution) public { + execute_UserOp(_user, _execution, hex"", false); } - function execute_UserOp(TestUser memory _user, Action memory _action, bool _shouldFail) public { - execute_UserOp(_user, _action, hex"", _shouldFail); + function execute_UserOp(TestUser memory _user, Execution memory _execution, bool _shouldFail) public { + execute_UserOp(_user, _execution, hex"", _shouldFail); } function execute_UserOp( TestUser memory _user, - Action memory _action, + Execution memory _execution, bytes memory _paymasterAndData, bool _shouldFail ) public { - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.execute.selector, _action); + bytes memory userOpCallData_ = abi.encodeWithSignature( + EXECUTE_SIGNATURE, + ModeLib.encodeSimpleSingle(), + ExecutionLib.encodeSingle(_execution.target, _execution.value, _execution.callData) + ); PackedUserOperation memory userOp_ = createUserOp(address(_user.deleGator), userOpCallData_, hex"", _paymasterAndData); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(_user, userOpHash_.toEthSignedMessageHash()); @@ -297,38 +304,42 @@ abstract contract BaseTest is Test { } function execute_UserOp(TestUser memory _user, bytes memory _callData) public { - Action memory action_ = Action({ to: address(_user.deleGator), value: 0, data: _callData }); - execute_UserOp(_user, action_); + Execution memory execution_ = Execution({ target: address(_user.deleGator), value: 0, callData: _callData }); + execute_UserOp(_user, execution_); } - function executeBatch_UserOp(TestUser memory _user, Action[] memory _actions) public { - bytes memory userOpCallData_ = abi.encodeWithSelector(IDeleGatorCoreFull.executeBatch.selector, _actions); + function executeBatch_UserOp(TestUser memory _user, Execution[] memory _executions) public { + bytes memory userOpCallData_ = + abi.encodeWithSignature(EXECUTE_SIGNATURE, ModeLib.encodeSimpleBatch(), abi.encode(_executions)); PackedUserOperation memory userOp_ = createUserOp(address(_user.deleGator), userOpCallData_); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(_user, userOpHash_.toEthSignedMessageHash()); submitUserOp_Bundler(userOp_, false); } - function invokeDelegation_UserOp(TestUser memory _user, Delegation[] memory _delegations, Action memory _action) public { - return invokeDelegation_UserOp(_user, _delegations, _action, hex""); + function invokeDelegation_UserOp(TestUser memory _user, Delegation[] memory _delegations, Execution memory _execution) public { + return invokeDelegation_UserOp(_user, _delegations, _execution, hex""); } function invokeDelegation_UserOp( TestUser memory _user, Delegation[] memory _delegations, - Action memory _action, + Execution memory _execution, bytes memory _initCode ) public { - bytes[] memory dataArray = new bytes[](1); - dataArray[0] = abi.encode(_delegations); + bytes[] memory permissionContexts_ = new bytes[](1); + permissionContexts_[0] = abi.encode(_delegations); + + bytes[] memory executionCallDatas_ = new bytes[](1); + executionCallDatas_[0] = ExecutionLib.encodeSingle(_execution.target, _execution.value, _execution.callData); - Action[] memory actions_ = new Action[](1); - actions_[0] = _action; + ModeCode[] memory modes_ = new ModeCode[](1); + modes_[0] = ModeLib.encodeSimpleSingle(); bytes memory userOpCallData_ = - abi.encodeWithSelector(IDeleGatorCoreFull.redeemDelegation.selector, dataArray, actions_); + abi.encodeWithSelector(DeleGatorCore.redeemDelegations.selector, permissionContexts_, modes_, executionCallDatas_); PackedUserOperation memory userOp_ = createUserOp(address(_user.deleGator), userOpCallData_, _initCode); bytes32 userOpHash_ = entryPoint.getUserOpHash(userOp_); userOp_.signature = signHash(_user, userOpHash_.toEthSignedMessageHash()); @@ -412,7 +423,7 @@ abstract contract BaseTest is Test { user_.addr = payable(addr_); user_.privateKey = privateKey_; (user_.x, user_.y) = FCL_ecdsa_utils.ecdsa_derivKpub(user_.privateKey); - user_.deleGator = IDeleGatorCoreFull(deployDeleGator(user_)); + user_.deleGator = DeleGatorCore(payable(deployDeleGator(user_))); vm.deal(address(user_.deleGator), 100 ether); vm.label(address(user_.deleGator), string.concat(_name, " DeleGator")); diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol new file mode 100644 index 0000000..b5677f7 --- /dev/null +++ b/test/utils/Constants.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT AND Apache-2.0 + +pragma solidity 0.8.23; + +string constant EXECUTE_SIGNATURE = "execute(bytes32,bytes)"; +string constant EXECUTE_SINGULAR_SIGNATURE = "execute((address,uint256,bytes))"; diff --git a/test/utils/MockCaveatEnforcer.sol b/test/utils/MockCaveatEnforcer.sol index c0d489f..9cab7da 100644 --- a/test/utils/MockCaveatEnforcer.sol +++ b/test/utils/MockCaveatEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { ModeCode } from "../../src/utils/Types.sol"; /** * @title MockCaveatEnforcer @@ -16,7 +16,7 @@ contract MockCaveatEnforcer is ICaveatEnforcer { * @dev Mocked implementation of the beforeHook function. * Increments the beforeHook call count. */ - function beforeHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external { + function beforeHook(bytes calldata, bytes calldata, ModeCode, bytes calldata, bytes32, address, address) external { beforeHookCallCount++; } @@ -24,7 +24,7 @@ contract MockCaveatEnforcer is ICaveatEnforcer { * @dev Mocked implementation of the afterHook function. * Increments the afterHook call count. */ - function afterHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external { + function afterHook(bytes calldata, bytes calldata, ModeCode, bytes calldata, bytes32, address, address) external { afterHookCallCount++; } } diff --git a/test/utils/MockFailureCaveatEnforcer.sol b/test/utils/MockFailureCaveatEnforcer.sol index 5eef1e1..1c5c80b 100644 --- a/test/utils/MockFailureCaveatEnforcer.sol +++ b/test/utils/MockFailureCaveatEnforcer.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { ICaveatEnforcer } from "../../src/interfaces/ICaveatEnforcer.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { ModeCode } from "../../src/utils/Types.sol"; /** * @title MockFailureCaveatEnforcer @@ -15,7 +15,7 @@ contract MockFailureCaveatEnforcer is ICaveatEnforcer { * @dev Mocked implementation of the beforeHook function. * Increments the beforeHook call count. */ - function beforeHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external { + function beforeHook(bytes calldata, bytes calldata, ModeCode, bytes calldata, bytes32, address, address) external { beforeHookCallCount++; } @@ -23,7 +23,7 @@ contract MockFailureCaveatEnforcer is ICaveatEnforcer { * @dev Mocked implementation of the afterHook function. * Increments the afterHook call count. */ - function afterHook(bytes calldata, bytes calldata, Action calldata, bytes32, address, address) external pure { + function afterHook(bytes calldata, bytes calldata, ModeCode, bytes calldata, bytes32, address, address) external pure { revert(); } } diff --git a/test/utils/PasswordCaveatEnforcer.t.sol b/test/utils/PasswordCaveatEnforcer.t.sol index 636c629..1903daa 100644 --- a/test/utils/PasswordCaveatEnforcer.t.sol +++ b/test/utils/PasswordCaveatEnforcer.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.23; import { CaveatEnforcer } from "../../src/enforcers/CaveatEnforcer.sol"; -import { Action } from "../../src/utils/Types.sol"; +import { Execution, ModeCode } from "../../src/utils/Types.sol"; /** * @title Password Enforcer @@ -18,7 +18,8 @@ contract PasswordEnforcer is CaveatEnforcer { function beforeHook( bytes calldata _terms, bytes calldata _args, - Action calldata, + ModeCode, + bytes calldata, bytes32, address, address diff --git a/test/utils/Types.t.sol b/test/utils/Types.t.sol index 299bd13..16329d5 100644 --- a/test/utils/Types.t.sol +++ b/test/utils/Types.t.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; -import { IDeleGatorCoreFull } from "../../src/interfaces/IDeleGatorCoreFull.sol"; +import { DeleGatorCore } from "../../src/DeleGatorCore.sol"; struct TestUser { string name; address payable addr; uint256 privateKey; - IDeleGatorCoreFull deleGator; + DeleGatorCore deleGator; uint256 x; uint256 y; }