diff --git a/.gas-snapshot b/.gas-snapshot index 1e133e36..1cb4c339 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -40,11 +40,11 @@ CrossRatePriceFeedTest:test_latestRoundData_invalidDenominatorPrice(int256) (run CrossRatePriceFeedTest:test_latestRoundData_invalidNumeratorPrice(int256) (runs: 256, μ: 907390, ~: 907952) CrossRatePriceFeedTest:test_latestRoundData_realValuesFork() (gas: 70243) CrossRatePriceFeedTest:test_latestRoundData_realValuesFuzz18(int256,int256) (runs: 256, μ: 1301519, ~: 1301597) -CrossRatePriceFeedTest:test_latestRoundData_realValuesFuzz8(int256,int256) (runs: 256, μ: 1301321, ~: 1301621) -CrossRatePriceFeedTest:test_latestRoundData_revertsOnOverflow(int256) (runs: 257, μ: 935241, ~: 935235) +CrossRatePriceFeedTest:test_latestRoundData_realValuesFuzz8(int256,int256) (runs: 256, μ: 1301315, ~: 1301621) +CrossRatePriceFeedTest:test_latestRoundData_revertsOnOverflow(int256) (runs: 256, μ: 935243, ~: 935235) CrossRatePriceFeedTest:test_latestRoundData_roundIdOne() (gas: 60318) -CrossRatePriceFeedTest:test_latestRoundData_staleDenominatorPrice(uint256) (runs: 256, μ: 906768, ~: 907044) -CrossRatePriceFeedTest:test_latestRoundData_staleNumeratorPrice(uint256) (runs: 256, μ: 906770, ~: 907046) +CrossRatePriceFeedTest:test_latestRoundData_staleDenominatorPrice(uint256) (runs: 256, μ: 906854, ~: 907132) +CrossRatePriceFeedTest:test_latestRoundData_staleNumeratorPrice(uint256) (runs: 256, μ: 906768, ~: 907046) CrossRatePriceFeedTest:test_latestRoundData_startedAtZero() (gas: 60332) CrossRatePriceFeedTest:test_latestRoundData_usesEarlierUpdatedAt() (gas: 68898) DeactivateInstruction:test_deactivateInstruction_alreadyDeactivated() (gas: 20424) @@ -74,8 +74,8 @@ DeploymentAddressesTest:test_transferOnceERC20Action_deployedAddress() (gas: 650 DeploymentAddressesTest:test_treasury_deployedAddress() (gas: 389464) DeploymentAddressesTest:test_uniswapV3ExactInputAction_deployedAddress() (gas: 1826284) DeploymentAddressesTest:test_withdrawERC4626Action_deployedAddress() (gas: 864746) -DepositERC4626Test:test_depositERC4626_happyPath() (gas: 419978) -DepositERC4626Test:test_depositERC4626_insufficientBalance() (gas: 216555) +DepositERC4626Test:test_depositERC4626_happyPath() (gas: 481909) +DepositERC4626Test:test_depositERC4626_insufficientBalance() (gas: 258567) DepositERC4626Test:test_depositERC4626_maxDepositReached() (gas: 150609) DepositERC4626Test:test_depositERC4626_maxDepositTooLow() (gas: 38646) DepositERC4626Test:test_depositERC4626_minTotalSharesZero() (gas: 36832) @@ -83,24 +83,24 @@ DepositERC4626Test:test_depositERC4626_recipientZero() (gas: 36769) DepositERC4626Test:test_depositERC4626_totalSharesTooLow() (gas: 39187) DepositERC4626Test:test_depositERC4626_valueZero() (gas: 36815) DepositERC4626Test:test_depositERC4626_vaultZero() (gas: 36798) -EstimateCallOnceGasConstant:testFuzz_callOnce_gasConstant(uint256,(address,bool,uint256,uint256,uint16,bytes4,bytes,(address,uint256,uint256,uint256))) (runs: 256, μ: 4128, ~: 3894) +EstimateCallOnceGasConstant:testFuzz_callOnce_gasConstant(uint256,(address,bool,uint256,uint256,uint16,bytes4,bytes,(address,uint256,uint256,uint256))) (runs: 256, μ: 4127, ~: 3876) EstimateDeactivateInstructionGasConstant:testFuzz_deactivateInstruction_gasConstant(uint256,(bytes32,(address,uint256,uint256,uint256))) (runs: 256, μ: 1960, ~: 1914) -EstimateDepositERC4626GasConstant:testFuzz_depositERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4489, ~: 4416) -EstimateRefuelERC20GasConstant:testFuzz_refuelERC20_gasConstant(uint256,uint256,(address,address,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3026, ~: 3024) -EstimateRefuelGasConstant:testFuzz_refuel_gasConstant(uint256,uint256,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 2887, ~: 2826) -EstimateSweepCCTPGasConstant:testFuzz_sweepCCTP_gasConstant(uint256,uint256,(address,uint32,bytes32,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3364, ~: 3342) -EstimateSweepDepositERC4626GasConstant:testFuzz_sweepDepositERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3576, ~: 3534) -EstimateSweepERC20GasConstant:testFuzz_sweepERC20_gasConstant(uint256,uint256,(address,address,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3013, ~: 3024) +EstimateDepositERC4626GasConstant:testFuzz_depositERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4486, ~: 4434) +EstimateRefuelERC20GasConstant:testFuzz_refuelERC20_gasConstant(uint256,uint256,(address,address,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3014, ~: 3006) +EstimateRefuelGasConstant:testFuzz_refuel_gasConstant(uint256,uint256,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 2897, ~: 2835) +EstimateSweepCCTPGasConstant:testFuzz_sweepCCTP_gasConstant(uint256,uint256,(address,uint32,bytes32,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3356, ~: 3333) +EstimateSweepDepositERC4626GasConstant:testFuzz_sweepDepositERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3523, ~: 3516) +EstimateSweepERC20GasConstant:testFuzz_sweepERC20_gasConstant(uint256,uint256,(address,address,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3026, ~: 3042) EstimateSweepGasConstant:testFuzz_sweep_gasConstant(uint256,uint256,(address,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 2871, ~: 2808) -EstimateSweepUniswapV3GasConstant:testFuzz_sweepUniswapV3_gasConstant(uint256,uint256,(address,address,address,uint24,uint256,uint256,uint256,uint32,uint32,(address,uint256,uint256,uint256))) (runs: 256, μ: 4426, ~: 4407) -EstimateSweepWithdrawERC4626GasConstant:testFuzz_sweepWithdrawERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3284, ~: 3270) -EstimateTransferCCTPGasConstant:testFuzz_transferCCTP_gasConstant(uint256,uint256,(address,uint256,uint32,bytes32,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4239, ~: 4188) -EstimateTransferERC20GasConstant:testFuzz_transferERC20_gasConstant(uint256,uint256,(address,address,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4000, ~: 3960) +EstimateSweepUniswapV3GasConstant:testFuzz_sweepUniswapV3_gasConstant(uint256,uint256,(address,address,address,uint24,uint256,uint256,uint256,uint32,uint32,(address,uint256,uint256,uint256))) (runs: 256, μ: 4424, ~: 4398) +EstimateSweepWithdrawERC4626GasConstant:testFuzz_sweepWithdrawERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 3297, ~: 3297) +EstimateTransferCCTPGasConstant:testFuzz_transferCCTP_gasConstant(uint256,uint256,(address,uint256,uint32,bytes32,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4224, ~: 4206) +EstimateTransferERC20GasConstant:testFuzz_transferERC20_gasConstant(uint256,uint256,(address,address,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4009, ~: 3969) EstimateTransferGasConstant:testFuzz_transfer_gasConstant(uint256,uint256,(address,uint256,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 3766, ~: 3762) -EstimateTransferOnceERC20GasConstant:testFuzz_transferERC20Once_gasConstant(uint256,(address,address,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 2562, ~: 2586) +EstimateTransferOnceERC20GasConstant:testFuzz_transferERC20Once_gasConstant(uint256,(address,address,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 2575, ~: 2586) EstimateTransferOnceGasConstant:testFuzz_transferOnce_gasConstant(uint256,(address,uint256,uint256,(address,uint256,uint256,uint256))) (runs: 256, μ: 2322, ~: 2298) -EstimateUniswapV3ExactInputGasConstant:testFuzz_uniswapV3ExactInput_gasConstant(uint256,uint256,(address,address,address,uint24,uint256,uint256,uint32,uint32,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 5314, ~: 5298) -EstimateWithdrawERC4626GasConstant:testFuzz_withdrawERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4243, ~: 4206) +EstimateUniswapV3ExactInputGasConstant:testFuzz_uniswapV3ExactInput_gasConstant(uint256,uint256,(address,address,address,uint24,uint256,uint256,uint32,uint32,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 5332, ~: 5316) +EstimateWithdrawERC4626GasConstant:testFuzz_withdrawERC4626_gasConstant(uint256,uint256,(address,address,uint256,uint256,(uint256,uint256,uint256,uint256),(address,uint256,uint256,uint256))) (runs: 256, μ: 4177, ~: 4170) FeeTokenRegistryTest:test_addFeeToken_alreadyRegistered() (gas: 1898) FeeTokenRegistryTest:test_addFeeToken_happyPath() (gas: 37590) FeeTokenRegistryTest:test_addFeeToken_roundIdZero() (gas: 12004) @@ -213,7 +213,7 @@ SweepCCTPTest:test_sweepCCTP_tokenNotSupported() (gas: 36792) SweepCCTPTest:test_sweepCCTP_tokenZero() (gas: 34886) SweepDepositERC4626Test:test_sweepDepositERC4626_balanceUnderThreshold() (gas: 38503) SweepDepositERC4626Test:test_sweepDepositERC4626_endBalanceOverThreshold() (gas: 35287) -SweepDepositERC4626Test:test_sweepDepositERC4626_happyPath() (gas: 398547) +SweepDepositERC4626Test:test_sweepDepositERC4626_happyPath() (gas: 460478) SweepDepositERC4626Test:test_sweepDepositERC4626_maxDepositReached() (gas: 149430) SweepDepositERC4626Test:test_sweepDepositERC4626_maxDepositTooLow() (gas: 36753) SweepDepositERC4626Test:test_sweepDepositERC4626_minTotalSharesZero() (gas: 35304) @@ -253,7 +253,7 @@ SweepUniswapV3Test:test_sweepUniswapV3_tokenToEth() (gas: 3042) SweepUniswapV3Test:test_sweepUniswapV3_tokenToToken() (gas: 3086) SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_balanceUnderThreshold() (gas: 56923) SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_endBalanceOverThreshold() (gas: 34904) -SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_happyPath() (gas: 320160) +SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_happyPath() (gas: 373047) SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_maxWithdrawReached() (gas: 100002) SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_maxWithdrawTooLow() (gas: 38358) SweepWithdrawERC4626Test:test_sweepWithdrawERC4626_recipientZero() (gas: 34875) @@ -312,7 +312,7 @@ UniswapV3ExactInputTest:test_uniswapV3ExactInput_recipientZero() (gas: 38513) UniswapV3ExactInputTest:test_uniswapV3ExactInput_sameToken() (gas: 38484) UniswapV3ExactInputTest:test_uniswapV3ExactInput_tokenToEth() (gas: 3042) UniswapV3ExactInputTest:test_uniswapV3ExactInput_tokenToToken() (gas: 3064) -WithdrawERC4626Test:test_withdrawERC4626_happyPath() (gas: 267185) +WithdrawERC4626Test:test_withdrawERC4626_happyPath() (gas: 302453) WithdrawERC4626Test:test_withdrawERC4626_maxWithdrawReached() (gas: 96775) WithdrawERC4626Test:test_withdrawERC4626_maxWithdrawTooLow() (gas: 37566) WithdrawERC4626Test:test_withdrawERC4626_recipientZero() (gas: 36481) diff --git a/src/actions/external/IERC7540.sol b/src/actions/external/IERC7540.sol new file mode 100644 index 00000000..bb71b45c --- /dev/null +++ b/src/actions/external/IERC7540.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.5.0; + +interface IERC7540Operator { + /** + * @dev The event emitted when an operator is set. + * + * @param controller The address of the controller. + * @param operator The address of the operator. + * @param approved The approval status. + */ + event OperatorSet(address indexed controller, address indexed operator, bool approved); + + /** + * @dev Sets or removes an operator for the caller. + * + * @param operator The address of the operator. + * @param approved The approval status. + * @return Whether the call was executed successfully or not + */ + function setOperator(address operator, bool approved) external returns (bool); + + /** + * @dev Returns `true` if the `operator` is approved as an operator for an `controller`. + * + * @param controller The address of the controller. + * @param operator The address of the operator. + * @return status The approval status + */ + function isOperator(address controller, address operator) external view returns (bool status); +} + +interface IERC7540Deposit { + event DepositRequest( + address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets + ); + /** + * @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit. + * + * - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow. + * - MUST revert if all of assets cannot be requested for deposit. + * - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller, + * approval of ERC-20 tokens from owner to sender is NOT enough. + * + * @param assets the amount of deposit assets to transfer from owner + * @param controller the controller of the request who will be able to operate the request + * @param owner the source of the deposit assets + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token. + */ + + function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId); + + /** + * @dev Returns the amount of requested assets in Pending state. + * + * - MUST NOT include any assets in Claimable state for deposit or mint. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function pendingDepositRequest(uint256 requestId, address controller) external view returns (uint256 pendingAssets); + + /** + * @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint. + * + * - MUST NOT include any assets in Pending state. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function claimableDepositRequest(uint256 requestId, address controller) + external + view + returns (uint256 claimableAssets); + + /** + * @dev Mints shares Vault shares to receiver by claiming the Request of the controller. + * + * - MUST emit the Deposit event. + * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator. + */ + function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares); + + /** + * @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller. + * + * - MUST emit the Deposit event. + * - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator. + */ + function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets); +} + +interface IERC7540Redeem { + event RedeemRequest( + address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets + ); + + /** + * @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem. + * + * - MUST support a redeem Request flow where the control of shares is taken from sender directly + * where msg.sender has ERC-20 approval over the shares of owner. + * - MUST revert if all of shares cannot be requested for redeem. + * + * @param shares the amount of shares to be redeemed to transfer from owner + * @param controller the controller of the request who will be able to operate the request + * @param owner the source of the shares to be redeemed + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault's share token. + */ + function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId); + + /** + * @dev Returns the amount of requested shares in Pending state. + * + * - MUST NOT include any shares in Claimable state for redeem or withdraw. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function pendingRedeemRequest(uint256 requestId, address controller) external view returns (uint256 pendingShares); + + /** + * @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw. + * + * - MUST NOT include any shares in Pending state for redeem or withdraw. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT revert unless due to integer overflow caused by an unreasonably large input. + */ + function claimableRedeemRequest(uint256 requestId, address controller) + external + view + returns (uint256 claimableShares); +}