diff --git a/.env.example b/.env.example index baf94d02..e2f9f29e 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,8 @@ ENTRYPOINT_ADDRESS=0x0000000071727De22E5E9d8BAf0edAc6f37da032 MULTISIG_DELEGATOR_IMPLEMENTATION_ADDRESS= META_SWAP_ADAPTER_OWNER_ADDRESS= METASWAP_ADDRESS= +SWAPS_API_SIGNER_ADDRESS= +ARGS_EQUALITY_CHECK_ENFORCER_ADDRESS= # Required for verifying contracts ETHERSCAN_API_KEY= diff --git a/script/DeployCaveatEnforcers.s.sol b/script/DeployCaveatEnforcers.s.sol index 2dd6a7ef..918726e0 100644 --- a/script/DeployCaveatEnforcers.s.sol +++ b/script/DeployCaveatEnforcers.s.sol @@ -19,7 +19,6 @@ import { ERC20PeriodTransferEnforcer } from "../src/enforcers/ERC20PeriodTransfe import { ERC721BalanceGteEnforcer } from "../src/enforcers/ERC721BalanceGteEnforcer.sol"; import { ERC721TransferEnforcer } from "../src/enforcers/ERC721TransferEnforcer.sol"; import { ERC1155BalanceGteEnforcer } from "../src/enforcers/ERC1155BalanceGteEnforcer.sol"; -import { ExactCalldataBatchEnforcer } from "../src/enforcers/ExactCalldataBatchEnforcer.sol"; import { ExactCalldataEnforcer } from "../src/enforcers/ExactCalldataEnforcer.sol"; import { ExactExecutionBatchEnforcer } from "../src/enforcers/ExactExecutionBatchEnforcer.sol"; import { ExactExecutionEnforcer } from "../src/enforcers/ExactExecutionEnforcer.sol"; @@ -104,9 +103,6 @@ contract DeployCaveatEnforcers is Script { deployedAddress = address(new ERC1155BalanceGteEnforcer{ salt: salt }()); console2.log("ERC1155BalanceGteEnforcer: %s", deployedAddress); - deployedAddress = address(new ExactCalldataBatchEnforcer{ salt: salt }()); - console2.log("ExactCalldataBatchEnforcer: %s", deployedAddress); - deployedAddress = address(new ExactCalldataEnforcer{ salt: salt }()); console2.log("ExactCalldataEnforcer: %s", deployedAddress); diff --git a/script/DeployDelegationMetaSwapAdapter.s.sol b/script/DeployDelegationMetaSwapAdapter.s.sol index 12a25cc9..41ce08fc 100644 --- a/script/DeployDelegationMetaSwapAdapter.s.sol +++ b/script/DeployDelegationMetaSwapAdapter.s.sol @@ -20,14 +20,18 @@ contract DeployDelegationMetaSwapAdapter is Script { bytes32 salt; address deployer; address metaSwapAdapterOwner; + address swapApiSignerEnforcer; IDelegationManager delegationManager; IMetaSwap metaSwap; + address argsEqualityCheckEnforcer; function setUp() public { salt = bytes32(abi.encodePacked(vm.envString("SALT"))); metaSwapAdapterOwner = vm.envAddress("META_SWAP_ADAPTER_OWNER_ADDRESS"); delegationManager = IDelegationManager(vm.envAddress("DELEGATION_MANAGER_ADDRESS")); metaSwap = IMetaSwap(vm.envAddress("METASWAP_ADDRESS")); + swapApiSignerEnforcer = vm.envAddress("SWAPS_API_SIGNER_ADDRESS"); + argsEqualityCheckEnforcer = vm.envAddress("ARGS_EQUALITY_CHECK_ENFORCER_ADDRESS"); deployer = msg.sender; console2.log("~~~"); console2.log("Deployer: %s", address(deployer)); @@ -40,8 +44,11 @@ contract DeployDelegationMetaSwapAdapter is Script { console2.log("~~~"); vm.startBroadcast(); - address delegationMetaSwapAdapter = - address(new DelegationMetaSwapAdapter{ salt: salt }(metaSwapAdapterOwner, delegationManager, metaSwap)); + address delegationMetaSwapAdapter = address( + new DelegationMetaSwapAdapter{ salt: salt }( + metaSwapAdapterOwner, swapApiSignerEnforcer, delegationManager, metaSwap, argsEqualityCheckEnforcer + ) + ); console2.log("DelegationMetaSwapAdapter: %s", delegationMetaSwapAdapter); vm.stopBroadcast(); diff --git a/src/helpers/DelegationMetaSwapAdapter.sol b/src/helpers/DelegationMetaSwapAdapter.sol index 746c718e..d173398c 100644 --- a/src/helpers/DelegationMetaSwapAdapter.sol +++ b/src/helpers/DelegationMetaSwapAdapter.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT AND Apache-2.0 pragma solidity 0.8.23; +import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; @@ -15,22 +17,47 @@ import { CALLTYPE_SINGLE, EXECTYPE_DEFAULT } from "../utils/Constants.sol"; /** * @title DelegationMetaSwapAdapter - * @notice Acts as a middleman to orchestrate token swaps using delegations - * and an aggregator (MetaSwap). + * @notice Acts as a middleman to orchestrate token swaps using delegations and an aggregator (MetaSwap). + * @dev This contract depends on an ArgsEqualityCheckEnforcer. The root delegation must include a caveat + * with this enforcer as its first element. Its arguments indicate whether the swap should enforce the token + * whitelist ("Token-Whitelist-Enforced") or not ("Token-Whitelist-Not-Enforced"). The root delegator is + * responsible for including this enforcer to signal the desired behavior. + * + * @dev This adapter is intended to be used with the Swaps API. Accordingly, all API requests must include a valid + * signature that incorporates an expiration timestamp. The signature is verified during swap execution to ensure + * that it is still valid. */ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { using ModeLib for ModeCode; using ExecutionLib for bytes; using SafeERC20 for IERC20; + struct SignatureData { + bytes apiData; + uint256 expiration; + bytes signature; + } + ////////////////////////////// State ////////////////////////////// + /// @dev Constant value used to enforce the token whitelist + string public constant WHITELIST_ENFORCED = "Token-Whitelist-Enforced"; + + /// @dev Constant value used to avoid enforcing the token whitelist + string public constant WHITELIST_NOT_ENFORCED = "Token-Whitelist-Not-Enforced"; + /// @dev The DelegationManager contract that has root access to this contract IDelegationManager public immutable delegationManager; /// @dev The MetaSwap contract used to swap tokens IMetaSwap public immutable metaSwap; + /// @dev The enforcer used to compare args and terms + address public immutable argsEqualityCheckEnforcer; + + /// @dev Address of the API signer account. + address public swapApiSigner; + /// @dev Indicates if a token is allowed to be used in the swaps mapping(IERC20 token => bool allowed) public isTokenAllowed; @@ -45,6 +72,9 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { /// @dev Emitted when the MetaSwap contract address is set. event SetMetaSwap(IMetaSwap indexed newMetaSwap); + /// @dev Emitted when the Args Equality Check Enforcer contract address is set. + event SetArgsEqualityCheckEnforcer(address indexed newArgsEqualityCheckEnforcer); + /// @dev Emitted when the contract sends tokens (or native tokens) to a recipient. event SentTokens(IERC20 indexed token, address indexed recipient, uint256 amount); @@ -54,6 +84,9 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { /// @dev Emitted when the allowed aggregator ID status changes. event ChangedAggregatorIdStatus(bytes32 indexed aggregatorIdHash, string aggregatorId, bool status); + /// @dev Emitted when the Signer API is updated. + event SwapApiSignerUpdated(address indexed newSigner); + ////////////////////////////// Errors ////////////////////////////// /// @dev Error thrown when the caller is not the delegation manager @@ -62,7 +95,7 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { /// @dev Error thrown when the call is not made by this contract itself. error NotSelf(); - /// @dev Error thrown when msg.sender is not the leaf delegatior. + /// @dev Error thrown when msg.sender is not the leaf delegator. error NotLeafDelegator(); /// @dev Error thrown when an execution with an unsupported CallType is made. @@ -87,7 +120,7 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { error TokenToIsNotAllowed(IERC20 token); /// @dev Error when the aggregator ID is not in the allow list. - error AggregatorIdIsNotAllowed(string); + error AggregatorIdIsNotAllowed(string aggregatorId); /// @dev Error when the input arrays of a function have different lengths. error InputLengthsMismatch(); @@ -104,6 +137,15 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { /// @dev Error when the amountFrom in the api data and swap data do not match. error AmountFromMismath(); + /// @dev Error when the delegations do not include the ArgsEqualityCheckEnforcer + error MissingArgsEqualityCheckEnforcer(); + + /// @dev Error thrown when API signature is invalid. + error InvalidApiSignature(); + + /// @dev Error thrown when the signature expiration has passed. + error SignatureExpired(); + ////////////////////////////// Modifiers ////////////////////////////// /** @@ -125,16 +167,31 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { ////////////////////////////// Constructor ////////////////////////////// /** - * @notice Initializes the DelegationMetaSwapAdapter contract - * @param _owner The initial owner of the contract - * @param _delegationManager the address of the trusted DelegationManager contract that will have root access to this contract - * @param _metaSwap the address of the trusted MetaSwap contract. + * @notice Initializes the DelegationMetaSwapAdapter contract. + * @param _owner The initial owner of the contract. + * @param _swapApiSigner The initial swap API signer. + * @param _delegationManager The address of the trusted DelegationManager contract has privileged access to call + * executeByExecutor based on a given delegation. + * @param _metaSwap The address of the trusted MetaSwap contract. + * @param _argsEqualityCheckEnforcer The address of the ArgsEqualityCheckEnforcer contract. */ - constructor(address _owner, IDelegationManager _delegationManager, IMetaSwap _metaSwap) Ownable(_owner) { + constructor( + address _owner, + address _swapApiSigner, + IDelegationManager _delegationManager, + IMetaSwap _metaSwap, + address _argsEqualityCheckEnforcer + ) + Ownable(_owner) + { + swapApiSigner = _swapApiSigner; delegationManager = _delegationManager; metaSwap = _metaSwap; + argsEqualityCheckEnforcer = _argsEqualityCheckEnforcer; + emit SwapApiSignerUpdated(_swapApiSigner); emit SetDelegationManager(_delegationManager); emit SetMetaSwap(_metaSwap); + emit SetArgsEqualityCheckEnforcer(_argsEqualityCheckEnforcer); } ////////////////////////////// External Methods ////////////////////////////// @@ -145,20 +202,34 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { receive() external payable { } /** - * @notice Executes a token swap using a delegation and transfers the swapped tokens to the root delegator. + * @notice Executes a token swap using a delegation and transfers the swapped tokens to the root delegator, after validating + * signature and expiration. * @dev The msg.sender must be the leaf delegator - * @param _apiData Encoded swap parameters, used by the aggregator. + * @param _signatureData Includes: + * - apiData Encoded swap parameters, used by the aggregator. + * - expiration Timestamp after which the signature is invalid. + * - signature Signature validating the provided apiData. * @param _delegations Array of Delegation objects containing delegation-specific data, sorted leaf to root. + * @param _useTokenWhitelist Indicates whether the tokens must be validated or not. */ - function swapByDelegation(bytes calldata _apiData, Delegation[] memory _delegations) external { + function swapByDelegation( + SignatureData calldata _signatureData, + Delegation[] memory _delegations, + bool _useTokenWhitelist + ) + external + { + _validateSignature(_signatureData); + (string memory aggregatorId_, IERC20 tokenFrom_, IERC20 tokenTo_, uint256 amountFrom_, bytes memory swapData_) = - _decodeApiData(_apiData); + _decodeApiData(_signatureData.apiData); uint256 delegationsLength_ = _delegations.length; if (delegationsLength_ == 0) revert InvalidEmptyDelegations(); if (tokenFrom_ == tokenTo_) revert InvalidIdenticalTokens(); - if (!isTokenAllowed[tokenFrom_]) revert TokenFromIsNotAllowed(tokenFrom_); - if (!isTokenAllowed[tokenTo_]) revert TokenToIsNotAllowed(tokenTo_); + + _validateTokens(tokenFrom_, tokenTo_, _delegations, _useTokenWhitelist); + if (!isAggregatorAllowed[keccak256(abi.encode(aggregatorId_))]) revert AggregatorIdIsNotAllowed(aggregatorId_); if (_delegations[0].delegator != msg.sender) revert NotLeafDelegator(); @@ -245,6 +316,15 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { _sendTokens(_tokenTo, obtainedAmount_, _recipient); } + /** + * @notice Updates the address authorized to sign API requests. + * @param _newSigner The new authorized signer address. + */ + function setSwapApiSigner(address _newSigner) external onlyOwner { + swapApiSigner = _newSigner; + emit SwapApiSignerUpdated(_newSigner); + } + /** * @notice Executes one calls on behalf of this contract, * authorized by the DelegationManager. @@ -350,6 +430,42 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { emit SentTokens(_token, _recipient, _amount); } + /** + * @dev Validates that the tokens are whitelisted or not based on the _useTokenWhitelist flag. + * @dev Adds the argsCheckEnforcer args to later validate if the token whitelist must be have been used or not. + * @param _tokenFrom The input token of the swap. + * @param _tokenTo The output token of the swap. + * @param _delegations The delegation chain; the last delegation must include the ArgsEqualityCheckEnforcer. + * @param _useTokenWhitelist Flag indicating whether token whitelist checks should be enforced. + */ + function _validateTokens( + IERC20 _tokenFrom, + IERC20 _tokenTo, + Delegation[] memory _delegations, + bool _useTokenWhitelist + ) + private + view + { + // The Args Enforcer must be the first caveat in the root delegation + uint256 lastIndex_ = _delegations.length - 1; + if ( + _delegations[lastIndex_].caveats.length == 0 + || _delegations[lastIndex_].caveats[0].enforcer != argsEqualityCheckEnforcer + ) { + revert MissingArgsEqualityCheckEnforcer(); + } + + // The args are set by this contract depending on the useTokenWhitelist flag + if (_useTokenWhitelist) { + if (!isTokenAllowed[_tokenFrom]) revert TokenFromIsNotAllowed(_tokenFrom); + if (!isTokenAllowed[_tokenTo]) revert TokenToIsNotAllowed(_tokenTo); + _delegations[lastIndex_].caveats[0].args = abi.encode(WHITELIST_ENFORCED); + } else { + _delegations[lastIndex_].caveats[0].args = abi.encode(WHITELIST_NOT_ENFORCED); + } + } + /** * @dev Internal helper to decode aggregator data from `apiData`. * @param _apiData Bytes that includes aggregatorId, tokenFrom, amountFrom, and the aggregator swap data. @@ -402,4 +518,18 @@ contract DelegationMetaSwapAdapter is ExecutionHelper, Ownable2Step { return _token.balanceOf(address(this)); } + + /** + * @dev Validates the expiration and signature of the provided apiData. + * @param _signatureData Contains the apiData, the expiration and signature. + */ + function _validateSignature(SignatureData memory _signatureData) private view { + if (block.timestamp > _signatureData.expiration) revert SignatureExpired(); + + bytes32 messageHash_ = keccak256(abi.encodePacked(_signatureData.apiData, _signatureData.expiration)); + bytes32 ethSignedMessageHash_ = MessageHashUtils.toEthSignedMessageHash(messageHash_); + + address recoveredSigner_ = ECDSA.recover(ethSignedMessageHash_, _signatureData.signature); + if (recoveredSigner_ != swapApiSigner) revert InvalidApiSignature(); + } } diff --git a/test/helpers/DelegationMetaSwapAdapter.t.sol b/test/helpers/DelegationMetaSwapAdapter.t.sol index df88dece..edbac019 100644 --- a/test/helpers/DelegationMetaSwapAdapter.t.sol +++ b/test/helpers/DelegationMetaSwapAdapter.t.sol @@ -20,6 +20,7 @@ import { AllowedCalldataEnforcer } from "../../src/enforcers/AllowedCalldataEnfo import { AllowedMethodsEnforcer } from "../../src/enforcers/AllowedMethodsEnforcer.sol"; import { ValueLteEnforcer } from "../../src/enforcers/ValueLteEnforcer.sol"; import { RedeemerEnforcer } from "../../src/enforcers/RedeemerEnforcer.sol"; +import { ArgsEqualityCheckEnforcer } from "../../src/enforcers/ArgsEqualityCheckEnforcer.sol"; import { BytesLib } from "@bytes-utils/BytesLib.sol"; import { MessageHashUtils } from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; import { DelegationManager } from "../../src/DelegationManager.sol"; @@ -53,10 +54,18 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest { AllowedTargetsEnforcer public allowedTargetsEnforcer; AllowedMethodsEnforcer public allowedMethodsEnforcer; ValueLteEnforcer public valueLteEnforcer; + ArgsEqualityCheckEnforcer public argsEqualityCheckEnforcer; RedeemerEnforcer public redeemerEnforcer; bytes public swapDataTokenAtoTokenB; + string public constant WHITELIST_ENFORCED = "Token-Whitelist-Enforced"; + string public constant WHITELIST_NOT_ENFORCED = "Token-Whitelist-Not-Enforced"; + bytes public argsEqualityEnforcerTerms = abi.encode(WHITELIST_ENFORCED); + + uint256 public swapSignerPrivateKey; + address public swapApiSignerAddress; + //////////////////////// Constructor & Setup //////////////////////// constructor() { @@ -72,10 +81,32 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest { allowedMethodsEnforcer = new AllowedMethodsEnforcer(); valueLteEnforcer = new ValueLteEnforcer(); redeemerEnforcer = new RedeemerEnforcer(); + argsEqualityCheckEnforcer = new ArgsEqualityCheckEnforcer(); + + (swapApiSignerAddress, swapSignerPrivateKey) = makeAddrAndKey("SWAP_API"); } //////////////////////// Internal / Private Helpers //////////////////////// + /** + * @dev Generates a valid signature for _apiData with a given _expiration. + */ + function _getValidSignature(bytes memory _apiData, uint256 _expiration) internal returns (bytes memory) { + bytes32 messageHash = keccak256(abi.encodePacked(_apiData, _expiration)); + bytes32 ethSignedMessageHash = MessageHashUtils.toEthSignedMessageHash(messageHash); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(swapSignerPrivateKey, ethSignedMessageHash); + return abi.encodePacked(r, s, v); + } + + /** + * @dev Builds and returns a SignatureData struct from the given apiData. + */ + function _buildSigData(bytes memory apiData) internal returns (DelegationMetaSwapAdapter.SignatureData memory) { + uint256 expiration = block.timestamp + 1000; + bytes memory signature = _getValidSignature(apiData, expiration); + return DelegationMetaSwapAdapter.SignatureData({ apiData: apiData, expiration: expiration, signature: signature }); + } + /** * @dev Internal helper to decode aggregator data from `apiData`. * Typically used in fork-based tests. @@ -142,10 +173,12 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest { } function _getCaveatsVaultDelegationNativeToken() private view returns (Caveat[] memory) { - Caveat[] memory caveats_ = new Caveat[](2); - caveats_[0] = Caveat({ args: hex"", enforcer: address(valueLteEnforcer), terms: abi.encode(uint256(10 ether)) }); + Caveat[] memory caveats_ = new Caveat[](3); + caveats_[0] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsEqualityEnforcerTerms }); + + caveats_[1] = Caveat({ args: hex"", enforcer: address(valueLteEnforcer), terms: abi.encode(uint256(10 ether)) }); - caveats_[1] = Caveat({ + caveats_[2] = Caveat({ args: hex"", enforcer: address(redeemerEnforcer), terms: abi.encodePacked(address(delegationMetaSwapAdapter)) @@ -154,19 +187,21 @@ abstract contract DelegationMetaSwapAdapterBaseTest is BaseTest { } function _getCaveatsVaultDelegationErc20() private view returns (Caveat[] memory) { - Caveat[] memory caveats_ = new Caveat[](4); - caveats_[0] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(address(tokenA)) }); + Caveat[] memory caveats_ = new Caveat[](5); + caveats_[0] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsEqualityEnforcerTerms }); - caveats_[1] = + caveats_[1] = Caveat({ args: hex"", enforcer: address(allowedTargetsEnforcer), terms: abi.encodePacked(address(tokenA)) }); + + caveats_[2] = Caveat({ args: hex"", enforcer: address(allowedMethodsEnforcer), terms: abi.encodePacked(IERC20.transfer.selector) }); uint256 paramStart_ = abi.encodeWithSelector(IERC20.transfer.selector).length; address paramValue_ = address(delegationMetaSwapAdapter); // The param start and and param value are packed together, but the param value is not packed. bytes memory inputTerms_ = abi.encodePacked(paramStart_, bytes32(uint256(uint160(paramValue_)))); - caveats_[2] = Caveat({ args: hex"", enforcer: address(allowedCalldataEnforcer), terms: inputTerms_ }); + caveats_[3] = Caveat({ args: hex"", enforcer: address(allowedCalldataEnforcer), terms: inputTerms_ }); - caveats_[3] = Caveat({ + caveats_[4] = Caveat({ args: hex"", enforcer: address(redeemerEnforcer), terms: abi.encodePacked(address(delegationMetaSwapAdapter)) @@ -283,9 +318,10 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), false); bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); vm.prank(address(subVault.deleGator)); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); uint256 vaultTokenAUsed_ = vaultTokenABalanceBefore_ - tokenA.balanceOf(address(vault.deleGator)); uint256 vaultTokenBObtained_ = tokenB.balanceOf(address(vault.deleGator)) - vaultTokenBBalanceBefore_; @@ -316,9 +352,10 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest // Prepare the swapData – note that tokenA is ETH (address(0)) bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), true); bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); vm.prank(address(subVault.deleGator)); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); // Calculate the change in balances. uint256 vaultEthUsed = vaultEthBalanceBefore - address(vault.deleGator).balance; @@ -350,9 +387,10 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest // Prepare the swapData – tokenTo is now ETH (address(0)). Note that _feeTo is false. bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), false); bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); vm.prank(address(subVault.deleGator)); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); // Calculate the change in balances. uint256 vaultTokenAUsed = vaultTokenABalanceBefore - tokenA.balanceOf(address(vault.deleGator)); @@ -361,6 +399,84 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest assertEq(vaultEthObtained, amountTo, "Vault should receive the correct amount of ETH"); } + // When _useTokenWhitelist is false, token whitelist checks are skipped. + // In this test, we first mark tokenA and tokenB as NOT allowed (so they would fail if checked) + // but the swap should succeed when _useTokenWhitelist is false. + function test_canSwapByDelegationsMock_withNoTokenWhitelist() public { + _setUpMockContracts(); + // Update allowed tokens: disable both tokens. + IERC20[] memory tokens_ = new IERC20[](2); + tokens_[0] = IERC20(tokenA); + tokens_[1] = IERC20(tokenB); + bool[] memory statuses_ = new bool[](2); + statuses_[0] = false; + statuses_[1] = false; + vm.prank(owner); + delegationMetaSwapAdapter.updateAllowedTokens(tokens_, statuses_); + assertFalse(delegationMetaSwapAdapter.isTokenAllowed(tokenA), "TokenA should be disabled"); + assertFalse(delegationMetaSwapAdapter.isTokenAllowed(tokenB), "TokenB should be disabled"); + + // Setting the args enforcer terms to skip the token whitelist + argsEqualityEnforcerTerms = abi.encode(WHITELIST_NOT_ENFORCED); + + // Build a valid delegation chain (which includes the argsEqualityCheckEnforcer in the first caveat). + Delegation[] memory delegations_ = new Delegation[](2); + Delegation memory vaultDelegation_ = _getVaultDelegation(); + Delegation memory subVaultDelegation_ = _getSubVaultDelegation(EncoderLib._getDelegationHash(vaultDelegation_)); + delegations_[1] = vaultDelegation_; + delegations_[0] = subVaultDelegation_; + + uint256 vaultTokenABalanceBefore_ = tokenA.balanceOf(address(vault.deleGator)); + uint256 vaultTokenBBalanceBefore_ = tokenB.balanceOf(address(vault.deleGator)); + + bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), true); + bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + + // Call swapByDelegation with _useTokenWhitelist set to false. + // Since whitelist checks are skipped, the swap should proceed even though tokenA and tokenB are not allowed. + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, false); + + uint256 vaultTokenAUsed_ = vaultTokenABalanceBefore_ - tokenA.balanceOf(address(vault.deleGator)); + uint256 vaultTokenBObtained_ = tokenB.balanceOf(address(vault.deleGator)) - vaultTokenBBalanceBefore_; + assertEq(vaultTokenAUsed_, amountFrom, "Vault should spend the specified amount of tokenA"); + assertEq(vaultTokenBObtained_, amountTo, "Vault should receive the correct amount of tokenB"); + } + + // The redeemer tries to swapByDelegation passing a flag different from what the delegator indicated + function test_revert_swapByDelegationsMock_withNoTokenWhitelistAndIncorrectArgs() public { + _setUpMockContracts(); + // Update allowed tokens: disable both tokens. + IERC20[] memory tokens_ = new IERC20[](2); + tokens_[0] = IERC20(tokenA); + tokens_[1] = IERC20(tokenB); + bool[] memory statuses_ = new bool[](2); + statuses_[0] = false; + statuses_[1] = false; + vm.prank(owner); + delegationMetaSwapAdapter.updateAllowedTokens(tokens_, statuses_); + + // Build a valid delegation chain (which includes the argsEqualityCheckEnforcer in the first caveat). + // The args indicate to use the token whitelist but the function the flag is set to not use the whitelist + // the difference between the expected and obtained args reverts + Delegation[] memory delegations_ = new Delegation[](2); + Delegation memory vaultDelegation_ = _getVaultDelegation(); + Delegation memory subVaultDelegation_ = _getSubVaultDelegation(EncoderLib._getDelegationHash(vaultDelegation_)); + delegations_[1] = vaultDelegation_; + delegations_[0] = subVaultDelegation_; + + bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), true); + bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + + // Call swapByDelegation with _useTokenWhitelist set to false. + vm.prank(address(subVault.deleGator)); + + vm.expectRevert("ArgsEqualityCheckEnforcer:different-args-and-terms"); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, false); + } + /// @notice Verifies that only the current owner can initiate ownership transfer. function test_revert_transferOwnership_ifNotOwner() public { _setUpMockContracts(); @@ -536,31 +652,37 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest _setUpMockContracts(); bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapDataTokenAtoTokenB); Delegation[] memory emptyDelegations_ = new Delegation[](0); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); vm.expectRevert(DelegationMetaSwapAdapter.InvalidEmptyDelegations.selector); - delegationMetaSwapAdapter.swapByDelegation(apiData_, emptyDelegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, emptyDelegations_, true); } // Test that swapByDelegation reverts when called from a non-leaf delegator function test_revert_swapByDelegation_nonLeafDelegator() public { _setUpMockContracts(); bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapDataTokenAtoTokenB); + Caveat[] memory caveats_ = new Caveat[](1); + caveats_[0] = Caveat({ args: hex"", enforcer: address(argsEqualityCheckEnforcer), terms: argsEqualityEnforcerTerms }); + Delegation memory delegation_ = Delegation({ delegate: address(delegationMetaSwapAdapter), delegator: address(vault.deleGator), authority: ROOT_AUTHORITY, - caveats: new Caveat[](0), + caveats: caveats_, salt: 0, signature: hex"" }); delegation_ = signDelegation(vault, delegation_); Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = delegation_; + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); // Using invalid caller, must be the vault not subVault vm.prank(address(subVault.deleGator)); vm.expectRevert(DelegationMetaSwapAdapter.NotLeafDelegator.selector); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } // Test that swapByDelegation reverts if tokenFrom equals tokenTo. @@ -572,9 +694,11 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapDataIdentical_); Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); vm.expectRevert(DelegationMetaSwapAdapter.InvalidIdenticalTokens.selector); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } // Test that swapByDelegation reverts if tokenFrom is not allowed. @@ -592,9 +716,11 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); vm.expectRevert(abi.encodeWithSelector(DelegationMetaSwapAdapter.TokenFromIsNotAllowed.selector, tokenA)); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } // Test that swapByDelegation reverts if tokenTo is not allowed. @@ -612,9 +738,11 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); vm.expectRevert(abi.encodeWithSelector(DelegationMetaSwapAdapter.TokenToIsNotAllowed.selector, tokenB)); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } // Test that swapByDelegation reverts if the aggregator ID is not allowed. @@ -632,9 +760,11 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); vm.expectRevert(abi.encodeWithSelector(DelegationMetaSwapAdapter.AggregatorIdIsNotAllowed.selector, aggregatorId)); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } // Test that swapTokens reverts when insufficient tokens are received. @@ -675,6 +805,30 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest ); } + // When the last delegation is missing the argsEqualityCheckEnforcer, + // swapByDelegation should revert with MissingArgsEqualityCheckEnforcer. + function test_revert_swapByDelegation_missingArgsEqualityCheckEnforcer() public { + _setUpMockContracts(); + bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapDataTokenAtoTokenB); + + // Create a vault delegation and remove its caveats (so that the check fails) + Delegation memory badVaultDelegation_ = _getVaultDelegation(); + // Remove caveats so that its length is zero + delete badVaultDelegation_.caveats; + + // Build the delegation chain with the modified vault delegation. + Delegation[] memory delegations_ = new Delegation[](2); + delegations_[1] = badVaultDelegation_; // last (root) delegation + delegations_[0] = _getSubVaultDelegation(EncoderLib._getDelegationHash(badVaultDelegation_)); + + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + + vm.prank(address(subVault.deleGator)); + vm.expectRevert(DelegationMetaSwapAdapter.MissingArgsEqualityCheckEnforcer.selector); + // Call the new version with _useTokenWhitelist (value here is irrelevant) + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); + } + // Test the withdraw function for an ERC20 token. function test_withdraw() public { _setUpMockContracts(); @@ -846,10 +1000,12 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(invalidApiData_); + // Call swapByDelegation from the subVault's perspective vm.prank(address(subVault.deleGator)); vm.expectRevert(DelegationMetaSwapAdapter.InvalidSwapFunctionSelector.selector); - delegationMetaSwapAdapter.swapByDelegation(invalidApiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } function test_revert_swapByDelegation_tokenFromMismatch() public { @@ -860,10 +1016,11 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(validApiData_); vm.prank(address(subVault.deleGator)); vm.expectRevert(DelegationMetaSwapAdapter.TokenFromMismath.selector); - delegationMetaSwapAdapter.swapByDelegation(validApiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } function test_revert_swapByDelegation_amountFromMismatch() public { @@ -899,23 +1056,130 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest Delegation[] memory delegations_ = new Delegation[](1); delegations_[0] = _getVaultDelegation(); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + vm.prank(address(subVault.deleGator)); vm.expectRevert(DelegationMetaSwapAdapter.AmountFromMismath.selector); - delegationMetaSwapAdapter.swapByDelegation(apiData_, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } - // Test that the constructor emits the SetDelegationManager and SetMetaSwap events. - function test_event_constructor_SetDelegationManager_SetMetaSwap() public { + // Test that the constructor emits the constructor events and assigns their values + function test_event_constructor_events() public { // Use dummy addresses for testing. + address dummySwapApiSignerAddress_ = address(0x999); address dummyDelegationManager_ = address(0x123); address dummyMetaSwap_ = address(0x456); + address dummyArgsEqualityCheckEnforcer_ = address(0x456); + // Expect the events to be emitted during construction. vm.expectEmit(true, true, false, true); + emit DelegationMetaSwapAdapter.SwapApiSignerUpdated(dummySwapApiSignerAddress_); + vm.expectEmit(true, true, false, true); emit DelegationMetaSwapAdapter.SetDelegationManager(IDelegationManager(dummyDelegationManager_)); vm.expectEmit(true, true, false, true); emit DelegationMetaSwapAdapter.SetMetaSwap(IMetaSwap(dummyMetaSwap_)); + vm.expectEmit(true, true, false, true); + emit DelegationMetaSwapAdapter.SetArgsEqualityCheckEnforcer(dummyArgsEqualityCheckEnforcer_); // Deploy a new instance to capture the events. - new DelegationMetaSwapAdapter(owner, IDelegationManager(dummyDelegationManager_), IMetaSwap(dummyMetaSwap_)); + DelegationMetaSwapAdapter adapter_ = new DelegationMetaSwapAdapter( + owner, + dummySwapApiSignerAddress_, + IDelegationManager(dummyDelegationManager_), + IMetaSwap(dummyMetaSwap_), + dummyArgsEqualityCheckEnforcer_ + ); + assertEq(adapter_.owner(), owner, "Constructor did not set owner correctly"); + assertEq( + address(adapter_.delegationManager()), dummyDelegationManager_, "Constructor did not set delegationManager correctly" + ); + assertEq(address(adapter_.swapApiSigner()), dummySwapApiSignerAddress_, "Constructor did not set swapApiSigner correctly"); + assertEq(address(adapter_.metaSwap()), dummyMetaSwap_, "Constructor did not set metaSwap correctly"); + assertEq( + adapter_.argsEqualityCheckEnforcer(), + dummyArgsEqualityCheckEnforcer_, + "Constructor did not set ArgsEqualityCheckEnforcer correctly" + ); + } + + // Test that allowance increases when it is zero. + function test_swapTokens_increasesAllowanceIfNeeded() public { + _setUpMockContracts(); + // Start with zero allowance for tokenA. + vm.prank(address(delegationMetaSwapAdapter)); + tokenA.approve(address(metaSwapMock), 0); + // Mint tokenA to the adapter. + vm.prank(owner); + tokenA.mint(address(delegationMetaSwapAdapter), amountFrom); + // Call swapTokens directly (simulate an internal call by using vm.prank(address(delegationMetaSwapAdapter))). + vm.prank(address(delegationMetaSwapAdapter)); + delegationMetaSwapAdapter.swapTokens( + aggregatorId, tokenA, tokenB, address(vault.deleGator), amountFrom, 0, swapDataTokenAtoTokenB + ); + uint256 allowanceAfter_ = tokenA.allowance(address(delegationMetaSwapAdapter), address(metaSwapMock)); + assertEq(allowanceAfter_, type(uint256).max, "Allowance should be increased to max"); + } + + /// @notice Tests that the owner can update the swap API signer via setSwapApiSigner and that the event is emitted. + function test_setSwapApiSigner_updatesStateAndEmitsEvent() public { + _setUpMockContracts(); + address newSigner_ = makeAddr("NewSwapSigner"); + vm.prank(owner); + vm.expectEmit(true, true, false, true); + emit DelegationMetaSwapAdapter.SwapApiSignerUpdated(newSigner_); + delegationMetaSwapAdapter.setSwapApiSigner(newSigner_); + assertEq(delegationMetaSwapAdapter.swapApiSigner(), newSigner_, "Swap API signer was not updated"); + } + + /// @notice Tests that a non-owner calling setSwapApiSigner reverts. + function test_revert_setSwapApiSigner_ifNotOwner() public { + _setUpMockContracts(); + address newSigner_ = makeAddr("NewSwapSigner"); + vm.prank(address(subVault.deleGator)); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, address(subVault.deleGator))); + delegationMetaSwapAdapter.setSwapApiSigner(newSigner_); + } + + /// @notice Tests that swapByDelegation reverts with SignatureExpired when the signature expiration has passed. + function test_revert_swapByDelegation_signatureExpired() public { + _setUpMockContracts(); + bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), true); + bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + // Set expiration in the past. + uint256 expiredTime = block.timestamp - 1; + bytes memory signature = _getValidSignature(apiData_, expiredTime); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = + DelegationMetaSwapAdapter.SignatureData({ apiData: apiData_, expiration: expiredTime, signature: signature }); + + Delegation[] memory delegations_ = new Delegation[](2); + Delegation memory vaultDelegation_ = _getVaultDelegation(); + Delegation memory subVaultDelegation_ = _getSubVaultDelegation(EncoderLib._getDelegationHash(vaultDelegation_)); + delegations_[1] = vaultDelegation_; + delegations_[0] = subVaultDelegation_; + + vm.prank(address(subVault.deleGator)); + vm.expectRevert(DelegationMetaSwapAdapter.SignatureExpired.selector); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); + } + + /// @notice Tests that swapByDelegation reverts with InvalidApiSignature when the signature is invalid. + function test_revert_swapByDelegation_invalidApiSignature() public { + _setUpMockContracts(); + bytes memory swapData_ = _encodeSwapData(IERC20(tokenA), IERC20(tokenB), amountFrom, amountTo, hex"", 0, address(0), true); + bytes memory apiData_ = _encodeApiData(aggregatorId, IERC20(tokenA), amountFrom, swapData_); + + // Changing the signer private key so the signer is different + swapSignerPrivateKey = 11111; + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(apiData_); + + Delegation[] memory delegations_ = new Delegation[](2); + Delegation memory vaultDelegation_ = _getVaultDelegation(); + Delegation memory subVaultDelegation_ = _getSubVaultDelegation(EncoderLib._getDelegationHash(vaultDelegation_)); + delegations_[1] = vaultDelegation_; + delegations_[0] = subVaultDelegation_; + + vm.prank(address(subVault.deleGator)); + vm.expectRevert(DelegationMetaSwapAdapter.InvalidApiSignature.selector); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); } /** @@ -940,8 +1204,13 @@ contract DelegationMetaSwapAdapterMockTest is DelegationMetaSwapAdapterBaseTest metaSwapMock = IMetaSwap(address(new MetaSwapMock(IERC20(tokenA), IERC20(tokenB)))); - delegationMetaSwapAdapter = - new DelegationMetaSwapAdapter(owner, IDelegationManager(address(delegationManager)), metaSwapMock); + delegationMetaSwapAdapter = new DelegationMetaSwapAdapter( + owner, + swapApiSignerAddress, + IDelegationManager(address(delegationManager)), + metaSwapMock, + address(argsEqualityCheckEnforcer) + ); vm.startPrank(owner); @@ -1017,8 +1286,11 @@ contract DelegationMetaSwapAdapterForkTest is DelegationMetaSwapAdapterBaseTest uint256 vaultTokenFromBalanceBefore_ = tokenFrom_.balanceOf(address(vault.deleGator)); uint256 vaultTokenToBalanceBefore_ = tokenTo_.balanceOf(address(vault.deleGator)); + + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(API_DATA_ERC20_TO_ERC20); + vm.prank(address(subVault.deleGator)); - delegationMetaSwapAdapter.swapByDelegation(API_DATA_ERC20_TO_ERC20, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); uint256 vaultTokenFromUsed_ = vaultTokenFromBalanceBefore_ - tokenFrom_.balanceOf(address(vault.deleGator)); uint256 vaultTokenToObtained_ = tokenTo_.balanceOf(address(vault.deleGator)) - vaultTokenToBalanceBefore_; @@ -1044,9 +1316,10 @@ contract DelegationMetaSwapAdapterForkTest is DelegationMetaSwapAdapterBaseTest // Record vault's ETH and tokenB balances before swap. uint256 vaultEthBalanceBefore = address(vault.deleGator).balance; uint256 vaultTokenBBalanceBefore = tokenTo_.balanceOf(address(vault.deleGator)); + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(API_DATA_NATIVE_TO_ERC20); vm.prank(address(subVault.deleGator)); - delegationMetaSwapAdapter.swapByDelegation(API_DATA_NATIVE_TO_ERC20, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); // Calculate the change in balances. uint256 vaultEthUsed = vaultEthBalanceBefore - address(vault.deleGator).balance; @@ -1072,9 +1345,10 @@ contract DelegationMetaSwapAdapterForkTest is DelegationMetaSwapAdapterBaseTest uint256 vaultTokenFromBalanceBefore_ = tokenFrom_.balanceOf(address(vault.deleGator)); uint256 vaultTokenToBalanceBefore_ = address(vault.deleGator).balance; + DelegationMetaSwapAdapter.SignatureData memory sigData_ = _buildSigData(API_DATA_ERC20_TO_NATIVE); vm.prank(address(subVault.deleGator)); - delegationMetaSwapAdapter.swapByDelegation(API_DATA_ERC20_TO_NATIVE, delegations_); + delegationMetaSwapAdapter.swapByDelegation(sigData_, delegations_, true); uint256 vaultTokenFromUsed_ = vaultTokenFromBalanceBefore_ - tokenFrom_.balanceOf(address(vault.deleGator)); uint256 vaultTokenToObtained_ = address(vault.deleGator).balance - vaultTokenToBalanceBefore_; @@ -1098,7 +1372,9 @@ contract DelegationMetaSwapAdapterForkTest is DelegationMetaSwapAdapterBaseTest { // Overriding values entryPoint = ENTRY_POINT_FORK; - delegationMetaSwapAdapter = new DelegationMetaSwapAdapter(owner, DELEGATION_MANAGER_FORK, META_SWAP_FORK); + delegationMetaSwapAdapter = new DelegationMetaSwapAdapter( + owner, swapApiSignerAddress, DELEGATION_MANAGER_FORK, META_SWAP_FORK, address(argsEqualityCheckEnforcer) + ); delegationManager = DelegationManager(address(DELEGATION_MANAGER_FORK)); hybridDeleGatorImpl = HYBRID_DELEGATOR_IMPL_FORK;