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(); + } +}