More Info
Private Name Tags
ContractCreator
Latest 8 from a total of 8 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Forward Dust To ... | 21464530 | 3 days ago | IN | 0 ETH | 0.00039505 | ||||
Forward Dust To ... | 21394972 | 13 days ago | IN | 0 ETH | 0.00126393 | ||||
Forward Dust To ... | 21394950 | 13 days ago | IN | 0 ETH | 0.00140683 | ||||
Forward Dust To ... | 21235553 | 35 days ago | IN | 0 ETH | 0.00072636 | ||||
Forward Dust To ... | 21235361 | 35 days ago | IN | 0 ETH | 0.00051381 | ||||
Forward Dust To ... | 21094687 | 55 days ago | IN | 0 ETH | 0.00043209 | ||||
Forward Dust To ... | 21094687 | 55 days ago | IN | 0 ETH | 0.00051797 | ||||
Forward Dust To ... | 21094687 | 55 days ago | IN | 0 ETH | 0.00037891 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
21004209 | 67 days ago | 0.15 ETH | ||||
21004209 | 67 days ago | 0.15 ETH | ||||
20904645 | 81 days ago | 0.11582021 ETH | ||||
20904645 | 81 days ago | 0.11582021 ETH | ||||
20776012 | 99 days ago | 2.75 ETH | ||||
20776012 | 99 days ago | 2.75 ETH | ||||
20716086 | 108 days ago | 0.10995388 ETH | ||||
20716086 | 108 days ago | 0.10995388 ETH | ||||
20706679 | 109 days ago | 0.1 ETH | ||||
20706679 | 109 days ago | 0.1 ETH | ||||
20696877 | 110 days ago | 3 ETH | ||||
20696877 | 110 days ago | 3 ETH | ||||
20670552 | 114 days ago | 12 ETH | ||||
20670552 | 114 days ago | 12 ETH | ||||
20667048 | 115 days ago | 0.0001 ETH | ||||
20667048 | 115 days ago | 0.0001 ETH | ||||
20648294 | 117 days ago | 0.1 ETH | ||||
20648294 | 117 days ago | 0.1 ETH | ||||
20641559 | 118 days ago | 1.15 ETH | ||||
20641559 | 118 days ago | 1.15 ETH | ||||
20640437 | 118 days ago | 0.01985082 ETH | ||||
20640437 | 118 days ago | 0.01985082 ETH | ||||
20624956 | 120 days ago | 0.9 ETH | ||||
20624956 | 120 days ago | 0.9 ETH | ||||
20619473 | 121 days ago | 0.5 ETH |
Loading...
Loading
Minimal Proxy Contract for 0x58f8cef0d825b1a609fad0576d5f2b7399ab1335
Contract Name:
ERC4626Form
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { ERC4626FormImplementation } from "src/forms/ERC4626FormImplementation.sol"; import { BaseForm } from "src/BaseForm.sol"; import { InitSingleVaultData } from "src/types/DataTypes.sol"; /// @title ERC4626Form /// @dev The Form implementation for normal ERC4626 vaults /// @author Zeropoint Labs contract ERC4626Form is ERC4626FormImplementation { ////////////////////////////////////////////////////////////// // CONSTANTS // ////////////////////////////////////////////////////////////// uint8 constant stateRegistryId = 1; // CoreStateRegistry ////////////////////////////////////////////////////////////// // CONSTRUCTOR // ////////////////////////////////////////////////////////////// constructor(address superRegistry_) ERC4626FormImplementation(superRegistry_, stateRegistryId) { } ////////////////////////////////////////////////////////////// // INTERNAL FUNCTIONS // ////////////////////////////////////////////////////////////// /// @inheritdoc BaseForm function _directDepositIntoVault( InitSingleVaultData memory singleVaultData_, address /*srcSender_*/ ) internal override returns (uint256 shares) { shares = _processDirectDeposit(singleVaultData_); } /// @inheritdoc BaseForm function _xChainDepositIntoVault( InitSingleVaultData memory singleVaultData_, address, /*srcSender_*/ uint64 srcChainId_ ) internal override returns (uint256 shares) { shares = _processXChainDeposit(singleVaultData_, srcChainId_); } /// @inheritdoc BaseForm function _directWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address /*srcSender_*/ ) internal override returns (uint256 assets) { assets = _processDirectWithdraw(singleVaultData_); } /// @inheritdoc BaseForm function _xChainWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address, /*srcSender_*/ uint64 srcChainId_ ) internal override returns (uint256 assets) { assets = _processXChainWithdraw(singleVaultData_, srcChainId_); } /// @inheritdoc BaseForm function _emergencyWithdraw(address receiverAddress_, uint256 amount_) internal override { _processEmergencyWithdraw(receiverAddress_, amount_); } /// @inheritdoc BaseForm function _forwardDustToPaymaster(address token_) internal override { _processForwardDustToPaymaster(token_); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { BaseForm } from "src/BaseForm.sol"; import { LiquidityHandler } from "src/crosschain-liquidity/LiquidityHandler.sol"; import { IBridgeValidator } from "src/interfaces/IBridgeValidator.sol"; import { Error } from "src/libraries/Error.sol"; import { DataLib } from "src/libraries/DataLib.sol"; import { InitSingleVaultData } from "src/types/DataTypes.sol"; import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import { IERC20Metadata } from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import { IERC4626 } from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol"; /// @title ERC4626FormImplementation /// @dev Has common ERC4626 internal functions that can be re-used by implementations /// @author Zeropoint Labs abstract contract ERC4626FormImplementation is BaseForm, LiquidityHandler { using SafeERC20 for IERC20; using SafeERC20 for IERC4626; using DataLib for uint256; ////////////////////////////////////////////////////////////// // CONSTANTS // ////////////////////////////////////////////////////////////// uint8 internal immutable STATE_REGISTRY_ID; uint256 internal constant ENTIRE_SLIPPAGE = 10_000; ////////////////////////////////////////////////////////////// // STRUCTS // ////////////////////////////////////////////////////////////// struct DirectDepositLocalVars { uint64 chainId; address asset; address bridgeValidator; uint256 shares; uint256 balanceBefore; uint256 assetDifference; uint256 nonce; uint256 deadline; uint256 inputAmount; bytes signature; } struct DirectWithdrawLocalVars { uint64 chainId; address asset; address bridgeValidator; uint256 amount; } struct XChainWithdrawLocalVars { uint64 dstChainId; address asset; address bridgeValidator; uint256 balanceBefore; uint256 balanceAfter; uint256 amount; } ////////////////////////////////////////////////////////////// // CONSTRUCTOR // ////////////////////////////////////////////////////////////// constructor(address superRegistry_, uint8 stateRegistryId_) BaseForm(superRegistry_) { /// @dev check if state registry id is valid superRegistry.getStateRegistry(stateRegistryId_); STATE_REGISTRY_ID = stateRegistryId_; } ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @inheritdoc BaseForm function getVaultName() public view virtual override returns (string memory) { return IERC4626(vault).name(); } /// @inheritdoc BaseForm function getVaultSymbol() public view virtual override returns (string memory) { return IERC4626(vault).symbol(); } /// @inheritdoc BaseForm function getVaultDecimals() public view virtual override returns (uint256) { return uint256(IERC4626(vault).decimals()); } /// @inheritdoc BaseForm function getPricePerVaultShare() public view virtual override returns (uint256) { uint256 vaultDecimals = IERC4626(vault).decimals(); return IERC4626(vault).convertToAssets(10 ** vaultDecimals); } /// @inheritdoc BaseForm function getVaultShareBalance() public view virtual override returns (uint256) { return IERC4626(vault).balanceOf(address(this)); } /// @inheritdoc BaseForm function getTotalAssets() public view virtual override returns (uint256) { return IERC4626(vault).totalAssets(); } /// @inheritdoc BaseForm function getTotalSupply() public view virtual override returns (uint256) { return IERC4626(vault).totalSupply(); } /// @inheritdoc BaseForm function getPreviewPricePerVaultShare() public view virtual override returns (uint256) { uint256 vaultDecimals = IERC4626(vault).decimals(); return IERC4626(vault).previewRedeem(10 ** vaultDecimals); } /// @inheritdoc BaseForm function previewDepositTo(uint256 assets_) public view virtual override returns (uint256) { return IERC4626(vault).convertToShares(assets_); } /// @inheritdoc BaseForm function previewWithdrawFrom(uint256 assets_) public view virtual override returns (uint256) { return IERC4626(vault).previewWithdraw(assets_); } /// @inheritdoc BaseForm function previewRedeemFrom(uint256 shares_) public view virtual override returns (uint256) { return IERC4626(vault).previewRedeem(shares_); } /// @inheritdoc BaseForm function superformYieldTokenName() external view virtual override returns (string memory) { return string(abi.encodePacked(IERC20Metadata(vault).name(), " SuperPosition")); } /// @inheritdoc BaseForm function superformYieldTokenSymbol() external view virtual override returns (string memory) { return string(abi.encodePacked("sp-", IERC20Metadata(vault).symbol())); } /// @inheritdoc BaseForm function getStateRegistryId() external view override returns (uint8) { return STATE_REGISTRY_ID; } ////////////////////////////////////////////////////////////// // INTERNAL FUNCTIONS // ////////////////////////////////////////////////////////////// function _processDirectDeposit(InitSingleVaultData memory singleVaultData_) internal returns (uint256 shares) { DirectDepositLocalVars memory vars; IERC4626 v = IERC4626(vault); vars.asset = address(asset); vars.balanceBefore = IERC20(vars.asset).balanceOf(address(this)); IERC20 token = IERC20(singleVaultData_.liqData.token); if (address(token) != NATIVE && singleVaultData_.liqData.txData.length == 0) { /// @dev this is only valid if token == asset (no txData) if (singleVaultData_.liqData.token != vars.asset) revert Error.DIFFERENT_TOKENS(); /// @dev handles the asset token transfers. if (token.allowance(msg.sender, address(this)) < singleVaultData_.amount) { revert Error.INSUFFICIENT_ALLOWANCE_FOR_DEPOSIT(); } /// @dev transfers input token, which is the same as vault asset, to the form token.safeTransferFrom(msg.sender, address(this), singleVaultData_.amount); } /// @dev non empty txData means there is a swap needed before depositing (input asset not the same as vault /// asset) if (singleVaultData_.liqData.txData.length != 0) { vars.bridgeValidator = superRegistry.getBridgeValidator(singleVaultData_.liqData.bridgeId); vars.chainId = CHAIN_ID; vars.inputAmount = IBridgeValidator(vars.bridgeValidator).decodeAmountIn(singleVaultData_.liqData.txData, false); if (address(token) != NATIVE) { /// @dev checks the allowance before transfer from router if (token.allowance(msg.sender, address(this)) < vars.inputAmount) { revert Error.INSUFFICIENT_ALLOWANCE_FOR_DEPOSIT(); } /// @dev transfers input token, which is different from the vault asset, to the form token.safeTransferFrom(msg.sender, address(this), vars.inputAmount); } IBridgeValidator(vars.bridgeValidator).validateTxData( IBridgeValidator.ValidateTxDataArgs( singleVaultData_.liqData.txData, vars.chainId, vars.chainId, vars.chainId, true, address(this), msg.sender, address(token), address(0) ) ); _dispatchTokens( superRegistry.getBridgeAddress(singleVaultData_.liqData.bridgeId), singleVaultData_.liqData.txData, address(token), vars.inputAmount, singleVaultData_.liqData.nativeAmount ); if ( IBridgeValidator(vars.bridgeValidator).decodeSwapOutputToken(singleVaultData_.liqData.txData) != vars.asset ) { revert Error.DIFFERENT_TOKENS(); } } vars.assetDifference = IERC20(vars.asset).balanceOf(address(this)) - vars.balanceBefore; /// @dev the difference in vault tokens, ready to be deposited, is compared with the amount inscribed in the /// superform data if ( vars.assetDifference * ENTIRE_SLIPPAGE < singleVaultData_.amount * (ENTIRE_SLIPPAGE - singleVaultData_.maxSlippage) ) { revert Error.DIRECT_DEPOSIT_SWAP_FAILED(); } /// @dev notice that vars.assetDifference is deposited regardless if txData exists or not /// @dev this presumes no dust is left in the superform IERC20(vars.asset).safeIncreaseAllowance(vault, vars.assetDifference); /// @dev deposit assets for shares and add extra validation check to ensure intended ERC4626 behavior shares = _depositAndValidate(singleVaultData_, v, vars.assetDifference); } function _processXChainDeposit( InitSingleVaultData memory singleVaultData_, uint64 srcChainId_ ) internal returns (uint256 shares) { (,, uint64 dstChainId) = singleVaultData_.superformId.getSuperform(); address vaultLoc = vault; IERC4626 v = IERC4626(vaultLoc); if (IERC20(asset).allowance(msg.sender, address(this)) < singleVaultData_.amount) { revert Error.INSUFFICIENT_ALLOWANCE_FOR_DEPOSIT(); } /// @dev pulling from sender, to auto-send tokens back in case of failed deposits / reverts IERC20(asset).safeTransferFrom(msg.sender, address(this), singleVaultData_.amount); /// @dev allowance is modified inside of the IERC20.transferFrom() call IERC20(asset).safeIncreaseAllowance(vaultLoc, singleVaultData_.amount); /// @dev deposit assets for shares and add extra validation check to ensure intended ERC4626 behavior shares = _depositAndValidate(singleVaultData_, v, singleVaultData_.amount); emit Processed(srcChainId_, dstChainId, singleVaultData_.payloadId, singleVaultData_.amount, vaultLoc); } function _processDirectWithdraw(InitSingleVaultData memory singleVaultData_) internal returns (uint256 assets) { DirectWithdrawLocalVars memory vars; /// @dev if there is no txData, on withdraws the receiver is receiverAddress, otherwise it /// is this contract (before swap) IERC4626 v = IERC4626(vault); IERC20 a = IERC20(asset); if (!singleVaultData_.retain4626) { vars.asset = address(asset); /// @dev redeem shares for assets and add extra validation check to ensure intended ERC4626 behavior assets = _withdrawAndValidate(singleVaultData_, v, a); if (singleVaultData_.liqData.txData.length != 0) { vars.bridgeValidator = superRegistry.getBridgeValidator(singleVaultData_.liqData.bridgeId); vars.amount = IBridgeValidator(vars.bridgeValidator).decodeAmountIn(singleVaultData_.liqData.txData, false); /// @dev the amount inscribed in liqData must be less or equal than the amount redeemed from the vault /// @dev if less it should be within the slippage limit specified by the user /// @dev important to maintain so that the keeper cannot update with malicious data after successful /// withdraw if (_isWithdrawTxDataAmountInvalid(vars.amount, assets, singleVaultData_.maxSlippage)) { revert Error.DIRECT_WITHDRAW_INVALID_LIQ_REQUEST(); } vars.chainId = CHAIN_ID; /// @dev validate and perform the swap to desired output token and send to beneficiary IBridgeValidator(vars.bridgeValidator).validateTxData( IBridgeValidator.ValidateTxDataArgs( singleVaultData_.liqData.txData, vars.chainId, vars.chainId, singleVaultData_.liqData.liqDstChainId, false, address(this), singleVaultData_.receiverAddress, vars.asset, address(0) ) ); _dispatchTokens( superRegistry.getBridgeAddress(singleVaultData_.liqData.bridgeId), singleVaultData_.liqData.txData, vars.asset, vars.amount, singleVaultData_.liqData.nativeAmount ); } } else { /// @dev transfer shares to user and do not redeem shares for assets v.safeTransfer(singleVaultData_.receiverAddress, singleVaultData_.amount); return 0; } } function _processXChainWithdraw( InitSingleVaultData memory singleVaultData_, uint64 srcChainId_ ) internal returns (uint256 assets) { XChainWithdrawLocalVars memory vars; uint256 len = singleVaultData_.liqData.txData.length; /// @dev a case where the withdraw req liqData has a valid token and tx data is not updated by the keeper if (singleVaultData_.liqData.token != address(0) && len == 0) { revert Error.WITHDRAW_TX_DATA_NOT_UPDATED(); } else if (singleVaultData_.liqData.token == address(0) && len != 0) { revert Error.WITHDRAW_TOKEN_NOT_UPDATED(); } (,, vars.dstChainId) = singleVaultData_.superformId.getSuperform(); IERC4626 v = IERC4626(vault); IERC20 a = IERC20(asset); if (!singleVaultData_.retain4626) { vars.asset = address(asset); /// @dev redeem shares for assets and add extra validation check to ensure intended ERC4626 behavior assets = _withdrawAndValidate(singleVaultData_, v, a); if (len != 0) { vars.bridgeValidator = superRegistry.getBridgeValidator(singleVaultData_.liqData.bridgeId); vars.amount = IBridgeValidator(vars.bridgeValidator).decodeAmountIn(singleVaultData_.liqData.txData, false); /// @dev the amount inscribed in liqData must be less or equal than the amount redeemed from the vault /// @dev if less it should be within the slippage limit specified by the user /// @dev important to maintain so that the keeper cannot update with malicious data after successful /// withdraw if (_isWithdrawTxDataAmountInvalid(vars.amount, assets, singleVaultData_.maxSlippage)) { revert Error.XCHAIN_WITHDRAW_INVALID_LIQ_REQUEST(); } /// @dev validate and perform the swap to desired output token and send to beneficiary IBridgeValidator(vars.bridgeValidator).validateTxData( IBridgeValidator.ValidateTxDataArgs( singleVaultData_.liqData.txData, vars.dstChainId, srcChainId_, singleVaultData_.liqData.liqDstChainId, false, address(this), singleVaultData_.receiverAddress, vars.asset, address(0) ) ); _dispatchTokens( superRegistry.getBridgeAddress(singleVaultData_.liqData.bridgeId), singleVaultData_.liqData.txData, vars.asset, vars.amount, singleVaultData_.liqData.nativeAmount ); } } else { /// @dev transfer shares to user and do not redeem shares for assets v.safeTransfer(singleVaultData_.receiverAddress, singleVaultData_.amount); return 0; } emit Processed(srcChainId_, vars.dstChainId, singleVaultData_.payloadId, singleVaultData_.amount, vault); } function _depositAndValidate( InitSingleVaultData memory singleVaultData_, IERC4626 v, uint256 assetDifference ) internal returns (uint256 shares) { address sharesReceiver = singleVaultData_.retain4626 ? singleVaultData_.receiverAddress : address(this); uint256 sharesBalanceBefore = v.balanceOf(sharesReceiver); shares = v.deposit(assetDifference, sharesReceiver); uint256 sharesBalanceAfter = v.balanceOf(sharesReceiver); if ( (sharesBalanceAfter - sharesBalanceBefore != shares) || ( ENTIRE_SLIPPAGE * shares < ((singleVaultData_.outputAmount * (ENTIRE_SLIPPAGE - singleVaultData_.maxSlippage))) ) ) { revert Error.VAULT_IMPLEMENTATION_FAILED(); } } function _withdrawAndValidate( InitSingleVaultData memory singleVaultData_, IERC4626 v, IERC20 a ) internal returns (uint256 assets) { address assetsReceiver = singleVaultData_.liqData.txData.length == 0 ? singleVaultData_.receiverAddress : address(this); uint256 assetsBalanceBefore = a.balanceOf(assetsReceiver); assets = v.redeem(singleVaultData_.amount, assetsReceiver, address(this)); uint256 assetsBalanceAfter = a.balanceOf(assetsReceiver); if ( (assetsBalanceAfter - assetsBalanceBefore != assets) || ( ENTIRE_SLIPPAGE * assets < ((singleVaultData_.outputAmount * (ENTIRE_SLIPPAGE - singleVaultData_.maxSlippage))) ) ) { revert Error.VAULT_IMPLEMENTATION_FAILED(); } if (assets == 0) revert Error.WITHDRAW_ZERO_COLLATERAL(); } function _isWithdrawTxDataAmountInvalid( uint256 bridgeDecodedAmount_, uint256 redeemedAmount_, uint256 slippage_ ) internal pure returns (bool isInvalid) { if ( bridgeDecodedAmount_ > redeemedAmount_ || ((bridgeDecodedAmount_ * ENTIRE_SLIPPAGE) < (redeemedAmount_ * (ENTIRE_SLIPPAGE - slippage_))) ) return true; } function _processEmergencyWithdraw(address receiverAddress_, uint256 amount_) internal { IERC4626 v = IERC4626(vault); if (receiverAddress_ == address(0)) revert Error.ZERO_ADDRESS(); if (v.balanceOf(address(this)) < amount_) { revert Error.INSUFFICIENT_BALANCE(); } v.safeTransfer(receiverAddress_, amount_); emit EmergencyWithdrawalProcessed(receiverAddress_, amount_); } function _processForwardDustToPaymaster(address token_) internal { if (token_ == address(0)) revert Error.ZERO_ADDRESS(); address paymaster = superRegistry.getAddress(keccak256("PAYMASTER")); IERC20 token = IERC20(token_); uint256 dust = token.balanceOf(address(this)); if (dust != 0) { token.safeTransfer(paymaster, dust); emit FormDustForwardedToPaymaster(token_, dust); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { IBaseForm } from "src/interfaces/IBaseForm.sol"; import { ISuperRegistry } from "src/interfaces/ISuperRegistry.sol"; import { ISuperformFactory } from "src/interfaces/ISuperformFactory.sol"; import { IEmergencyQueue } from "src/interfaces/IEmergencyQueue.sol"; import { DataLib } from "src/libraries/DataLib.sol"; import { Error } from "src/libraries/Error.sol"; import { InitSingleVaultData } from "src/types/DataTypes.sol"; import { Initializable } from "openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; import { ERC165 } from "openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; /// @title BaseForm /// @dev Abstract contract to be inherited by different Form implementations /// @author Zeropoint Labs abstract contract BaseForm is IBaseForm, Initializable, ERC165 { using DataLib for uint256; ////////////////////////////////////////////////////////////// // CONSTANTS // ////////////////////////////////////////////////////////////// ISuperRegistry public immutable superRegistry; uint64 public immutable CHAIN_ID; ////////////////////////////////////////////////////////////// // STATE VARIABLES // ////////////////////////////////////////////////////////////// /// @dev the address of the vault that was added address public vault; /// @dev underlying asset of vault this form pertains to address public asset; ////////////////////////////////////////////////////////////// // MODIFIERS // ////////////////////////////////////////////////////////////// modifier notPaused(InitSingleVaultData memory singleVaultData_) { if ( !ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY"))).isSuperform( singleVaultData_.superformId ) ) { revert Error.SUPERFORM_ID_NONEXISTENT(); } (, uint32 formImplementationId_,) = singleVaultData_.superformId.getSuperform(); if ( ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY"))).isFormImplementationPaused( formImplementationId_ ) ) revert Error.PAUSED(); _; } modifier onlySuperRouter() { if (superRegistry.getAddress(keccak256("SUPERFORM_ROUTER")) != msg.sender) revert Error.NOT_SUPERFORM_ROUTER(); _; } modifier onlyCoreStateRegistry() { if (superRegistry.getAddress(keccak256("CORE_STATE_REGISTRY")) != msg.sender) { revert Error.NOT_CORE_STATE_REGISTRY(); } _; } modifier onlyEmergencyQueue() { if (msg.sender != superRegistry.getAddress(keccak256("EMERGENCY_QUEUE"))) { revert Error.NOT_EMERGENCY_QUEUE(); } _; } ////////////////////////////////////////////////////////////// // CONSTRUCTOR // ////////////////////////////////////////////////////////////// constructor(address superRegistry_) { if (superRegistry_ == address(0)) { revert Error.ZERO_ADDRESS(); } if (block.chainid > type(uint64).max) { revert Error.BLOCK_CHAIN_ID_OUT_OF_BOUNDS(); } CHAIN_ID = uint64(block.chainid); superRegistry = ISuperRegistry(superRegistry_); _disableInitializers(); } ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @inheritdoc IBaseForm function superformYieldTokenName() external view virtual override returns (string memory); /// @inheritdoc IBaseForm function superformYieldTokenSymbol() external view virtual override returns (string memory); /// @inheritdoc IBaseForm function getStateRegistryId() external view virtual override returns (uint8); // @inheritdoc IBaseForm function getVaultAddress() external view override returns (address) { return vault; } // @inheritdoc IBaseForm function getVaultAsset() public view override returns (address) { return asset; } /// @inheritdoc IBaseForm function getVaultName() public view virtual override returns (string memory); /// @inheritdoc IBaseForm function getVaultSymbol() public view virtual override returns (string memory); /// @inheritdoc IBaseForm function getVaultDecimals() public view virtual override returns (uint256); /// @inheritdoc IBaseForm function getPricePerVaultShare() public view virtual override returns (uint256); /// @inheritdoc IBaseForm function getVaultShareBalance() public view virtual override returns (uint256); /// @inheritdoc IBaseForm function getTotalAssets() public view virtual override returns (uint256); /// @inheritdoc IBaseForm function getTotalSupply() public view virtual override returns (uint256); // @inheritdoc IBaseForm function getPreviewPricePerVaultShare() public view virtual override returns (uint256); /// @inheritdoc IBaseForm function previewDepositTo(uint256 assets_) public view virtual override returns (uint256); /// @inheritdoc IBaseForm function previewWithdrawFrom(uint256 assets_) public view virtual override returns (uint256); /// @inheritdoc IBaseForm function previewRedeemFrom(uint256 shares_) public view virtual override returns (uint256); ////////////////////////////////////////////////////////////// // EXTERNAL WRITE FUNCTIONS // ////////////////////////////////////////////////////////////// /// @param superRegistry_ ISuperRegistry address deployed /// @param vault_ The vault address this form pertains to /// @param asset_ The underlying asset address of the vault this form pertains to function initialize(address superRegistry_, address vault_, address asset_) external initializer { if (ISuperRegistry(superRegistry_) != superRegistry) revert Error.NOT_SUPER_REGISTRY(); if (vault_ == address(0) || asset_ == address(0)) revert Error.ZERO_ADDRESS(); vault = vault_; asset = asset_; } /// @inheritdoc IBaseForm function directDepositIntoVault( InitSingleVaultData memory singleVaultData_, address srcSender_ ) external payable override onlySuperRouter notPaused(singleVaultData_) returns (uint256 shares) { shares = _directDepositIntoVault(singleVaultData_, srcSender_); } /// @inheritdoc IBaseForm function directWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address srcSender_ ) external override onlySuperRouter returns (uint256 assets) { if (!_isPaused(singleVaultData_.superformId)) { assets = _directWithdrawFromVault(singleVaultData_, srcSender_); } else { IEmergencyQueue(superRegistry.getAddress(keccak256("EMERGENCY_QUEUE"))).queueWithdrawal(singleVaultData_); } } /// @inheritdoc IBaseForm function xChainDepositIntoVault( InitSingleVaultData memory singleVaultData_, address srcSender_, uint64 srcChainId_ ) external override onlyCoreStateRegistry notPaused(singleVaultData_) returns (uint256 shares) { if (srcChainId_ != 0 && srcChainId_ != CHAIN_ID) { shares = _xChainDepositIntoVault(singleVaultData_, srcSender_, srcChainId_); } else { revert Error.INVALID_CHAIN_ID(); } } /// @inheritdoc IBaseForm function xChainWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address srcSender_, uint64 srcChainId_ ) external override onlyCoreStateRegistry returns (uint256 assets) { if (srcChainId_ != 0 && srcChainId_ != CHAIN_ID) { if (!_isPaused(singleVaultData_.superformId)) { assets = _xChainWithdrawFromVault(singleVaultData_, srcSender_, srcChainId_); } else { IEmergencyQueue(superRegistry.getAddress(keccak256("EMERGENCY_QUEUE"))).queueWithdrawal( singleVaultData_ ); } } else { revert Error.INVALID_CHAIN_ID(); } } /// @inheritdoc IBaseForm function emergencyWithdraw(address receiverAddress_, uint256 amount_) external override onlyEmergencyQueue { _emergencyWithdraw(receiverAddress_, amount_); } /// @inheritdoc IBaseForm function forwardDustToPaymaster(address token_) external override { if (token_ == vault) revert Error.CANNOT_FORWARD_4646_TOKEN(); _forwardDustToPaymaster(token_); } /// @dev Checks if the Form implementation has the appropriate interface support /// @param interfaceId_ is the interfaceId to check function supportsInterface(bytes4 interfaceId_) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId_ == type(IBaseForm).interfaceId || super.supportsInterface(interfaceId_); } ////////////////////////////////////////////////////////////// // INTERNAL FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev Deposits underlying tokens into a vault function _directDepositIntoVault( InitSingleVaultData memory singleVaultData_, address srcSender_ ) internal virtual returns (uint256 shares); /// @dev Deposits underlying tokens into a vault function _xChainDepositIntoVault( InitSingleVaultData memory singleVaultData_, address srcSender_, uint64 srcChainId_ ) internal virtual returns (uint256 shares); /// @dev Withdraws underlying tokens from a vault function _directWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address srcSender_ ) internal virtual returns (uint256 assets); /// @dev Withdraws underlying tokens from a vault function _xChainWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address srcSender_, uint64 srcChainId_ ) internal virtual returns (uint256 assets); /// @dev withdraws vault shares from form during emergency function _emergencyWithdraw(address receiverAddress_, uint256 amount_) internal virtual; /// @dev forwards dust to paymaster function _forwardDustToPaymaster(address token_) internal virtual; /// @dev returns if a form id is paused function _isPaused(uint256 superformId) internal view returns (bool) { address factory = superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")); if (!ISuperformFactory(factory).isSuperform(superformId)) { revert Error.SUPERFORM_ID_NONEXISTENT(); } (, uint32 formImplementationId_,) = superformId.getSuperform(); return ISuperformFactory(factory).isFormImplementationPaused(formImplementationId_); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; /// @dev contains all the common struct and enums used for data communication between chains. /// @dev There are two transaction types in Superform Protocol enum TransactionType { DEPOSIT, WITHDRAW } /// @dev Message types can be INIT, RETURN (for successful Deposits) and FAIL (for failed withdraws) enum CallbackType { INIT, RETURN, FAIL } /// @dev Payloads are stored, updated (deposits) or processed (finalized) enum PayloadState { STORED, UPDATED, PROCESSED } /// @dev contains all the common struct used for interchain token transfers. struct LiqRequest { /// @dev generated data bytes txData; /// @dev input token for deposits, desired output token on target liqDstChainId for withdraws. Must be set for /// txData to be updated on destination for withdraws address token; /// @dev intermediary token on destination. Relevant for xChain deposits where a destination swap is needed for /// validation purposes address interimToken; /// @dev what bridge to use to move tokens uint8 bridgeId; /// @dev dstChainId = liqDstchainId for deposits. For withdraws it is the target chain id for where the underlying /// is to be delivered uint64 liqDstChainId; /// @dev currently this amount is used as msg.value in the txData call. uint256 nativeAmount; } /// @dev main struct that holds required multi vault data for an action struct MultiVaultSFData { // superformids must have same destination. Can have different underlyings uint256[] superformIds; uint256[] amounts; // on deposits, amount of token to deposit on dst, on withdrawals, superpositions to burn uint256[] outputAmounts; // on deposits, amount of shares to receive, on withdrawals, amount of assets to receive uint256[] maxSlippages; LiqRequest[] liqRequests; // if length = 1; amount = sum(amounts) | else amounts must match the amounts being sent bytes permit2data; bool[] hasDstSwaps; bool[] retain4626s; // if true, we don't mint SuperPositions, and send the 4626 back to the user instead address receiverAddress; /// this address must always be an EOA otherwise funds may be lost address receiverAddressSP; /// this address can be a EOA or a contract that implements onERC1155Receiver. must always be set for deposits bytes extraFormData; // extraFormData } /// @dev main struct that holds required single vault data for an action struct SingleVaultSFData { // superformids must have same destination. Can have different underlyings uint256 superformId; uint256 amount; uint256 outputAmount; // on deposits, amount of shares to receive, on withdrawals, amount of assets to receive uint256 maxSlippage; LiqRequest liqRequest; // if length = 1; amount = sum(amounts)| else amounts must match the amounts being sent bytes permit2data; bool hasDstSwap; bool retain4626; // if true, we don't mint SuperPositions, and send the 4626 back to the user instead address receiverAddress; /// this address must always be an EOA otherwise funds may be lost address receiverAddressSP; /// this address can be a EOA or a contract that implements onERC1155Receiver. must always be set for deposits bytes extraFormData; // extraFormData } /// @dev overarching struct for multiDst requests with multi vaults struct MultiDstMultiVaultStateReq { uint8[][] ambIds; uint64[] dstChainIds; MultiVaultSFData[] superformsData; } /// @dev overarching struct for single cross chain requests with multi vaults struct SingleXChainMultiVaultStateReq { uint8[] ambIds; uint64 dstChainId; MultiVaultSFData superformsData; } /// @dev overarching struct for multiDst requests with single vaults struct MultiDstSingleVaultStateReq { uint8[][] ambIds; uint64[] dstChainIds; SingleVaultSFData[] superformsData; } /// @dev overarching struct for single cross chain requests with single vaults struct SingleXChainSingleVaultStateReq { uint8[] ambIds; uint64 dstChainId; SingleVaultSFData superformData; } /// @dev overarching struct for single direct chain requests with single vaults struct SingleDirectSingleVaultStateReq { SingleVaultSFData superformData; } /// @dev overarching struct for single direct chain requests with multi vaults struct SingleDirectMultiVaultStateReq { MultiVaultSFData superformData; } /// @dev struct for SuperRouter with re-arranged data for the message (contains the payloadId) /// @dev realize that receiverAddressSP is not passed, only needed on source chain to mint struct InitMultiVaultData { uint256 payloadId; uint256[] superformIds; uint256[] amounts; uint256[] outputAmounts; uint256[] maxSlippages; LiqRequest[] liqData; bool[] hasDstSwaps; bool[] retain4626s; address receiverAddress; bytes extraFormData; } /// @dev struct for SuperRouter with re-arranged data for the message (contains the payloadId) struct InitSingleVaultData { uint256 payloadId; uint256 superformId; uint256 amount; uint256 outputAmount; uint256 maxSlippage; LiqRequest liqData; bool hasDstSwap; bool retain4626; address receiverAddress; bytes extraFormData; } /// @dev struct for Emergency Queue struct QueuedWithdrawal { address receiverAddress; uint256 superformId; uint256 amount; uint256 srcPayloadId; bool isProcessed; } /// @dev all statuses of the timelock payload enum TimelockStatus { UNAVAILABLE, PENDING, PROCESSED } /// @dev holds information about the timelock payload struct TimelockPayload { uint8 isXChain; uint64 srcChainId; uint256 lockedTill; InitSingleVaultData data; TimelockStatus status; } /// @dev struct that contains the type of transaction, callback flags and other identification, as well as the vaults /// data in params struct AMBMessage { uint256 txInfo; // tight packing of TransactionType txType, CallbackType flag if multi/single vault, registry id, // srcSender and srcChainId bytes params; // decoding txInfo will point to the right datatype of params. Refer PayloadHelper.sol } /// @dev struct that contains the information required for broadcasting changes struct BroadcastMessage { bytes target; bytes32 messageType; bytes message; } /// @dev struct that contains info on returned data from destination struct ReturnMultiData { uint256 payloadId; uint256[] superformIds; uint256[] amounts; } /// @dev struct that contains info on returned data from destination struct ReturnSingleData { uint256 payloadId; uint256 superformId; uint256 amount; } /// @dev struct that contains the data on the fees to pay to the AMBs struct AMBExtraData { uint256[] gasPerAMB; bytes[] extraDataPerAMB; } /// @dev struct that contains the data on the fees to pay to the AMBs on broadcasts struct BroadCastAMBExtraData { uint256[] gasPerDst; bytes[] extraDataPerDst; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { Error } from "src/libraries/Error.sol"; import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; /// @title LiquidityHandler /// @dev Executes an action with tokens to either bridge from Chain A -> Chain B or swap on same chain /// @dev To be inherited by contracts that move liquidity /// @author ZeroPoint Labs abstract contract LiquidityHandler { using SafeERC20 for IERC20; ////////////////////////////////////////////////////////////// // CONSTANTS // ////////////////////////////////////////////////////////////// address constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; ////////////////////////////////////////////////////////////// // INTERNAL FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev dispatches tokens via a liquidity bridge or exchange /// @param bridge_ Bridge address to pass tokens to /// @param txData_ liquidity bridge data /// @param token_ Token caller deposits into superform /// @param amount_ Amount of tokens to deposit /// @param nativeAmount_ msg.value or msg.value + native tokens function _dispatchTokens( address bridge_, bytes memory txData_, address token_, uint256 amount_, uint256 nativeAmount_ ) internal virtual { if (amount_ == 0) { revert Error.ZERO_AMOUNT(); } if (bridge_ == address(0)) { revert Error.ZERO_ADDRESS(); } if (token_ != NATIVE) { IERC20(token_).safeIncreaseAllowance(bridge_, amount_); } else { if (nativeAmount_ < amount_) revert Error.INSUFFICIENT_NATIVE_AMOUNT(); if (nativeAmount_ > address(this).balance) revert Error.INSUFFICIENT_BALANCE(); } (bool success,) = payable(bridge_).call{ value: nativeAmount_ }(txData_); if (!success) revert Error.FAILED_TO_EXECUTE_TXDATA(token_); if (token_ != NATIVE) { IERC20 token = IERC20(token_); if (token.allowance(address(this), bridge_) > 0) token.forceApprove(bridge_, 0); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; /// @title Bridge Validator Interface /// @dev Interface all Bridge Validators must follow /// @author Zeropoint Labs interface IBridgeValidator { ////////////////////////////////////////////////////////////// // STRUCTS // ////////////////////////////////////////////////////////////// struct ValidateTxDataArgs { bytes txData; uint64 srcChainId; uint64 dstChainId; uint64 liqDstChainId; bool deposit; address superform; address receiverAddress; address liqDataToken; address liqDataInterimToken; } ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev validates the receiver of the liquidity request /// @param txData_ is the txData of the cross chain deposit /// @param receiver_ is the address of the receiver to validate /// @return valid_ if the address is valid function validateReceiver(bytes calldata txData_, address receiver_) external view returns (bool valid_); /// @dev validates the txData of a cross chain deposit /// @param args_ the txData arguments to validate in txData /// @return hasDstSwap if the txData contains a destination swap function validateTxData(ValidateTxDataArgs calldata args_) external view returns (bool hasDstSwap); /// @dev decodes the txData and returns the amount of input token on source /// @param txData_ is the txData of the cross chain deposit /// @param genericSwapDisallowed_ true if generic swaps are disallowed /// @return amount_ the amount expected function decodeAmountIn( bytes calldata txData_, bool genericSwapDisallowed_ ) external view returns (uint256 amount_); /// @dev decodes neccesary information for processing swaps on the destination chain /// @param txData_ is the txData to be decoded /// @return token_ is the address of the token /// @return amount_ the amount expected function decodeDstSwap(bytes calldata txData_) external pure returns (address token_, uint256 amount_); /// @dev decodes the final output token address (for only direct chain actions!) /// @param txData_ is the txData to be decoded /// @return token_ the address of the token function decodeSwapOutputToken(bytes calldata txData_) external pure returns (address token_); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; library Error { ////////////////////////////////////////////////////////////// // CONFIGURATION ERRORS // ////////////////////////////////////////////////////////////// ///@notice errors thrown in protocol setup /// @dev thrown if chain id exceeds max(uint64) error BLOCK_CHAIN_ID_OUT_OF_BOUNDS(); /// @dev thrown if not possible to revoke a role in broadcasting error CANNOT_REVOKE_NON_BROADCASTABLE_ROLES(); /// @dev thrown if not possible to revoke last admin error CANNOT_REVOKE_LAST_ADMIN(); /// @dev thrown if trying to set again pseudo immutables in super registry error DISABLED(); /// @dev thrown if rescue delay is not yet set for a chain error DELAY_NOT_SET(); /// @dev thrown if get native token price estimate in paymentHelper is 0 error INVALID_NATIVE_TOKEN_PRICE(); /// @dev thrown if wormhole refund chain id is not set error REFUND_CHAIN_ID_NOT_SET(); /// @dev thrown if wormhole relayer is not set error RELAYER_NOT_SET(); /// @dev thrown if a role to be revoked is not assigned error ROLE_NOT_ASSIGNED(); ////////////////////////////////////////////////////////////// // AUTHORIZATION ERRORS // ////////////////////////////////////////////////////////////// ///@notice errors thrown if functions cannot be called /// COMMON AUTHORIZATION ERRORS /// --------------------------------------------------------- /// @dev thrown if caller is not address(this), internal call error INVALID_INTERNAL_CALL(); /// @dev thrown if msg.sender is not a valid amb implementation error NOT_AMB_IMPLEMENTATION(); /// @dev thrown if msg.sender is not an allowed broadcaster error NOT_ALLOWED_BROADCASTER(); /// @dev thrown if msg.sender is not broadcast amb implementation error NOT_BROADCAST_AMB_IMPLEMENTATION(); /// @dev thrown if msg.sender is not broadcast state registry error NOT_BROADCAST_REGISTRY(); /// @dev thrown if msg.sender is not core state registry error NOT_CORE_STATE_REGISTRY(); /// @dev thrown if msg.sender is not emergency admin error NOT_EMERGENCY_ADMIN(); /// @dev thrown if msg.sender is not emergency queue error NOT_EMERGENCY_QUEUE(); /// @dev thrown if msg.sender is not minter error NOT_MINTER(); /// @dev thrown if msg.sender is not minter state registry error NOT_MINTER_STATE_REGISTRY_ROLE(); /// @dev thrown if msg.sender is not paymaster error NOT_PAYMASTER(); /// @dev thrown if msg.sender is not payment admin error NOT_PAYMENT_ADMIN(); /// @dev thrown if msg.sender is not protocol admin error NOT_PROTOCOL_ADMIN(); /// @dev thrown if msg.sender is not state registry error NOT_STATE_REGISTRY(); /// @dev thrown if msg.sender is not super registry error NOT_SUPER_REGISTRY(); /// @dev thrown if msg.sender is not superform router error NOT_SUPERFORM_ROUTER(); /// @dev thrown if msg.sender is not a superform error NOT_SUPERFORM(); /// @dev thrown if msg.sender is not superform factory error NOT_SUPERFORM_FACTORY(); /// @dev thrown if msg.sender is not timelock form error NOT_TIMELOCK_SUPERFORM(); /// @dev thrown if msg.sender is not timelock state registry error NOT_TIMELOCK_STATE_REGISTRY(); /// @dev thrown if msg.sender is not user or disputer error NOT_VALID_DISPUTER(); /// @dev thrown if the msg.sender is not privileged caller error NOT_PRIVILEGED_CALLER(bytes32 role); /// STATE REGISTRY AUTHORIZATION ERRORS /// --------------------------------------------------------- /// @dev layerzero adapter specific error, thrown if caller not layerzero endpoint error CALLER_NOT_ENDPOINT(); /// @dev hyperlane adapter specific error, thrown if caller not hyperlane mailbox error CALLER_NOT_MAILBOX(); /// @dev wormhole relayer specific error, thrown if caller not wormhole relayer error CALLER_NOT_RELAYER(); /// @dev thrown if src chain sender is not valid error INVALID_SRC_SENDER(); ////////////////////////////////////////////////////////////// // INPUT VALIDATION ERRORS // ////////////////////////////////////////////////////////////// ///@notice errors thrown if input variables are not valid /// COMMON INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if there is an array length mismatch error ARRAY_LENGTH_MISMATCH(); /// @dev thrown if payload id does not exist error INVALID_PAYLOAD_ID(); /// @dev error thrown when msg value should be zero in certain payable functions error MSG_VALUE_NOT_ZERO(); /// @dev thrown if amb ids length is 0 error ZERO_AMB_ID_LENGTH(); /// @dev thrown if address input is address 0 error ZERO_ADDRESS(); /// @dev thrown if amount input is 0 error ZERO_AMOUNT(); /// @dev thrown if final token is address 0 error ZERO_FINAL_TOKEN(); /// @dev thrown if value input is 0 error ZERO_INPUT_VALUE(); /// SUPERFORM ROUTER INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if the vaults data is invalid error INVALID_SUPERFORMS_DATA(); /// @dev thrown if receiver address is not set error RECEIVER_ADDRESS_NOT_SET(); /// SUPERFORM FACTORY INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if a form is not ERC165 compatible error ERC165_UNSUPPORTED(); /// @dev thrown if a form is not form interface compatible error FORM_INTERFACE_UNSUPPORTED(); /// @dev error thrown if form implementation address already exists error FORM_IMPLEMENTATION_ALREADY_EXISTS(); /// @dev error thrown if form implementation id already exists error FORM_IMPLEMENTATION_ID_ALREADY_EXISTS(); /// @dev thrown if a form does not exist error FORM_DOES_NOT_EXIST(); /// @dev thrown if form id is larger than max uint16 error INVALID_FORM_ID(); /// @dev thrown if superform not on factory error SUPERFORM_ID_NONEXISTENT(); /// @dev thrown if same vault and form implementation is used to create new superform error VAULT_FORM_IMPLEMENTATION_COMBINATION_EXISTS(); /// FORM INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if in case of no txData, if liqData.token != vault.asset() /// in case of txData, if token output of swap != vault.asset() error DIFFERENT_TOKENS(); /// @dev thrown if the amount in direct withdraw is not correct error DIRECT_WITHDRAW_INVALID_LIQ_REQUEST(); /// @dev thrown if the amount in xchain withdraw is not correct error XCHAIN_WITHDRAW_INVALID_LIQ_REQUEST(); /// LIQUIDITY BRIDGE INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if route id is blacklisted in socket error BLACKLISTED_ROUTE_ID(); /// @dev thrown if route id is not blacklisted in socket error NOT_BLACKLISTED_ROUTE_ID(); /// @dev error thrown when txData selector of lifi bridge is a blacklisted selector error BLACKLISTED_SELECTOR(); /// @dev error thrown when txData selector of lifi bridge is not a blacklisted selector error NOT_BLACKLISTED_SELECTOR(); /// @dev thrown if a certain action of the user is not allowed given the txData provided error INVALID_ACTION(); /// @dev thrown if in deposits, the liqDstChainId doesn't match the stateReq dstChainId error INVALID_DEPOSIT_LIQ_DST_CHAIN_ID(); /// @dev thrown if index is invalid error INVALID_INDEX(); /// @dev thrown if the chain id in the txdata is invalid error INVALID_TXDATA_CHAIN_ID(); /// @dev thrown if the validation of bridge txData fails due to a destination call present error INVALID_TXDATA_NO_DESTINATIONCALL_ALLOWED(); /// @dev thrown if the validation of bridge txData fails due to wrong receiver error INVALID_TXDATA_RECEIVER(); /// @dev thrown if the validation of bridge txData fails due to wrong token error INVALID_TXDATA_TOKEN(); /// @dev thrown if txData is not present (in case of xChain actions) error NO_TXDATA_PRESENT(); /// STATE REGISTRY INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if payload is being updated with final amounts length different than amounts length error DIFFERENT_PAYLOAD_UPDATE_AMOUNTS_LENGTH(); /// @dev thrown if payload is being updated with tx data length different than liq data length error DIFFERENT_PAYLOAD_UPDATE_TX_DATA_LENGTH(); /// @dev thrown if keeper update final token is different than the vault underlying error INVALID_UPDATE_FINAL_TOKEN(); /// @dev thrown if broadcast finality for wormhole is invalid error INVALID_BROADCAST_FINALITY(); /// @dev thrown if amb id is not valid leading to an address 0 of the implementation error INVALID_BRIDGE_ID(); /// @dev thrown if chain id involved in xchain message is invalid error INVALID_CHAIN_ID(); /// @dev thrown if payload update amount isn't equal to dst swapper amount error INVALID_DST_SWAP_AMOUNT(); /// @dev thrown if message amb and proof amb are the same error INVALID_PROOF_BRIDGE_ID(); /// @dev thrown if order of proof AMBs is incorrect, either duplicated or not incrementing error INVALID_PROOF_BRIDGE_IDS(); /// @dev thrown if rescue data lengths are invalid error INVALID_RESCUE_DATA(); /// @dev thrown if delay is invalid error INVALID_TIMELOCK_DELAY(); /// @dev thrown if amounts being sent in update payload mean a negative slippage error NEGATIVE_SLIPPAGE(); /// @dev thrown if slippage is outside of bounds error SLIPPAGE_OUT_OF_BOUNDS(); /// SUPERPOSITION INPUT VALIDATION ERRORS /// --------------------------------------------------------- /// @dev thrown if src senders mismatch in state sync error SRC_SENDER_MISMATCH(); /// @dev thrown if src tx types mismatch in state sync error SRC_TX_TYPE_MISMATCH(); ////////////////////////////////////////////////////////////// // EXECUTION ERRORS // ////////////////////////////////////////////////////////////// ///@notice errors thrown due to function execution logic /// COMMON EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if the swap in a direct deposit resulted in insufficient tokens error DIRECT_DEPOSIT_SWAP_FAILED(); /// @dev thrown if payload is not unique error DUPLICATE_PAYLOAD(); /// @dev thrown if native tokens fail to be sent to superform contracts error FAILED_TO_SEND_NATIVE(); /// @dev thrown if allowance is not correct to deposit error INSUFFICIENT_ALLOWANCE_FOR_DEPOSIT(); /// @dev thrown if contract has insufficient balance for operations error INSUFFICIENT_BALANCE(); /// @dev thrown if native amount is not at least equal to the amount in the request error INSUFFICIENT_NATIVE_AMOUNT(); /// @dev thrown if payload cannot be decoded error INVALID_PAYLOAD(); /// @dev thrown if payload status is invalid error INVALID_PAYLOAD_STATUS(); /// @dev thrown if payload type is invalid error INVALID_PAYLOAD_TYPE(); /// LIQUIDITY BRIDGE EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if we try to decode the final swap output token in a xChain liquidity bridging action error CANNOT_DECODE_FINAL_SWAP_OUTPUT_TOKEN(); /// @dev thrown if liquidity bridge fails for erc20 or native tokens error FAILED_TO_EXECUTE_TXDATA(address token); /// @dev thrown if asset being used for deposit mismatches in multivault deposits error INVALID_DEPOSIT_TOKEN(); /// STATE REGISTRY EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if bridge tokens haven't arrived to destination error BRIDGE_TOKENS_PENDING(); /// @dev thrown if withdrawal tx data cannot be updated error CANNOT_UPDATE_WITHDRAW_TX_DATA(); /// @dev thrown if rescue passed dispute deadline error DISPUTE_TIME_ELAPSED(); /// @dev thrown if message failed to reach the specified level of quorum needed error INSUFFICIENT_QUORUM(); /// @dev thrown if broadcast payload is invalid error INVALID_BROADCAST_PAYLOAD(); /// @dev thrown if broadcast fee is invalid error INVALID_BROADCAST_FEE(); /// @dev thrown if retry fees is less than required error INVALID_RETRY_FEE(); /// @dev thrown if broadcast message type is wrong error INVALID_MESSAGE_TYPE(); /// @dev thrown if payload hash is invalid during `retryMessage` on Layezero implementation error INVALID_PAYLOAD_HASH(); /// @dev thrown if update payload function was called on a wrong payload error INVALID_PAYLOAD_UPDATE_REQUEST(); /// @dev thrown if a state registry id is 0 error INVALID_REGISTRY_ID(); /// @dev thrown if a form state registry id is 0 error INVALID_FORM_REGISTRY_ID(); /// @dev thrown if trying to finalize the payload but the withdraw is still locked error LOCKED(); /// @dev thrown if payload is already updated (during xChain deposits) error PAYLOAD_ALREADY_UPDATED(); /// @dev thrown if payload is already processed error PAYLOAD_ALREADY_PROCESSED(); /// @dev thrown if payload is not in UPDATED state error PAYLOAD_NOT_UPDATED(); /// @dev thrown if rescue is still in timelocked state error RESCUE_LOCKED(); /// @dev thrown if rescue is already proposed error RESCUE_ALREADY_PROPOSED(); /// @dev thrown if payload hash is zero during `retryMessage` on Layezero implementation error ZERO_PAYLOAD_HASH(); /// DST SWAPPER EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if process dst swap is tried for processed payload id error DST_SWAP_ALREADY_PROCESSED(); /// @dev thrown if indices have duplicates error DUPLICATE_INDEX(); /// @dev thrown if failed dst swap is already updated error FAILED_DST_SWAP_ALREADY_UPDATED(); /// @dev thrown if indices are out of bounds error INDEX_OUT_OF_BOUNDS(); /// @dev thrown if failed swap token amount is 0 error INVALID_DST_SWAPPER_FAILED_SWAP(); /// @dev thrown if failed swap token amount is not 0 and if token balance is less than amount (non zero) error INVALID_DST_SWAPPER_FAILED_SWAP_NO_TOKEN_BALANCE(); /// @dev thrown if failed swap token amount is not 0 and if native amount is less than amount (non zero) error INVALID_DST_SWAPPER_FAILED_SWAP_NO_NATIVE_BALANCE(); /// @dev forbid xChain deposits with destination swaps without interim token set (for user protection) error INVALID_INTERIM_TOKEN(); /// @dev thrown if dst swap output is less than minimum expected error INVALID_SWAP_OUTPUT(); /// FORM EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if try to forward 4626 share from the superform error CANNOT_FORWARD_4646_TOKEN(); /// @dev thrown in KYCDAO form if no KYC token is present error NO_VALID_KYC_TOKEN(); /// @dev thrown in forms where a certain functionality is not allowed or implemented error NOT_IMPLEMENTED(); /// @dev thrown if form implementation is PAUSED, users cannot perform any action error PAUSED(); /// @dev thrown if shares != deposit output or assets != redeem output when minting SuperPositions error VAULT_IMPLEMENTATION_FAILED(); /// @dev thrown if withdrawal tx data is not updated error WITHDRAW_TOKEN_NOT_UPDATED(); /// @dev thrown if withdrawal tx data is not updated error WITHDRAW_TX_DATA_NOT_UPDATED(); /// @dev thrown when redeeming from vault yields zero collateral error WITHDRAW_ZERO_COLLATERAL(); /// PAYMENT HELPER EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if chainlink is reporting an improper price error CHAINLINK_MALFUNCTION(); /// @dev thrown if chainlink is reporting an incomplete round error CHAINLINK_INCOMPLETE_ROUND(); /// @dev thrown if feed decimals is not 8 error CHAINLINK_UNSUPPORTED_DECIMAL(); /// EMERGENCY QUEUE EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if emergency withdraw is not queued error EMERGENCY_WITHDRAW_NOT_QUEUED(); /// @dev thrown if emergency withdraw is already processed error EMERGENCY_WITHDRAW_PROCESSED_ALREADY(); /// SUPERPOSITION EXECUTION ERRORS /// --------------------------------------------------------- /// @dev thrown if uri cannot be updated error DYNAMIC_URI_FROZEN(); /// @dev thrown if tx history is not found while state sync error TX_HISTORY_NOT_FOUND(); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { Error } from "src/libraries/Error.sol"; library DataLib { function packTxInfo( uint8 txType_, uint8 callbackType_, uint8 multi_, uint8 registryId_, address srcSender_, uint64 srcChainId_ ) internal pure returns (uint256 txInfo) { txInfo = uint256(txType_); txInfo |= uint256(callbackType_) << 8; txInfo |= uint256(multi_) << 16; txInfo |= uint256(registryId_) << 24; txInfo |= uint256(uint160(srcSender_)) << 32; txInfo |= uint256(srcChainId_) << 192; } function decodeTxInfo(uint256 txInfo_) internal pure returns (uint8 txType, uint8 callbackType, uint8 multi, uint8 registryId, address srcSender, uint64 srcChainId) { txType = uint8(txInfo_); callbackType = uint8(txInfo_ >> 8); multi = uint8(txInfo_ >> 16); registryId = uint8(txInfo_ >> 24); srcSender = address(uint160(txInfo_ >> 32)); srcChainId = uint64(txInfo_ >> 192); } /// @dev returns the vault-form-chain pair of a superform /// @param superformId_ is the id of the superform /// @return superform_ is the address of the superform /// @return formImplementationId_ is the form id /// @return chainId_ is the chain id function getSuperform(uint256 superformId_) internal pure returns (address superform_, uint32 formImplementationId_, uint64 chainId_) { superform_ = address(uint160(superformId_)); formImplementationId_ = uint32(superformId_ >> 160); chainId_ = uint64(superformId_ >> 192); if (chainId_ == 0) { revert Error.INVALID_CHAIN_ID(); } } /// @dev returns the vault-form-chain pair of an array of superforms /// @param superformIds_ array of superforms /// @return superforms_ are the address of the vaults function getSuperforms(uint256[] memory superformIds_) internal pure returns (address[] memory superforms_) { uint256 len = superformIds_.length; superforms_ = new address[](len); for (uint256 i; i < len; ++i) { (superforms_[i],,) = getSuperform(superformIds_[i]); } } /// @dev returns the destination chain of a given superform /// @param superformId_ is the id of the superform /// @return chainId_ is the chain id function getDestinationChain(uint256 superformId_) internal pure returns (uint64 chainId_) { chainId_ = uint64(superformId_ >> 192); if (chainId_ == 0) { revert Error.INVALID_CHAIN_ID(); } } /// @dev generates the superformId /// @param superform_ is the address of the superform /// @param formImplementationId_ is the type of the form /// @param chainId_ is the chain id on which the superform is deployed function packSuperform( address superform_, uint32 formImplementationId_, uint64 chainId_ ) internal pure returns (uint256 superformId_) { superformId_ = uint256(uint160(superform_)); superformId_ |= uint256(formImplementationId_) << 160; superformId_ |= uint256(chainId_) << 192; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC-20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC-20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC-20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol"; import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { InitSingleVaultData } from "src/types/DataTypes.sol"; import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; import { IERC4626 } from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol"; /// @title IBaseForm /// @dev Interface for BaseForm /// @author ZeroPoint Labs interface IBaseForm is IERC165 { ////////////////////////////////////////////////////////////// // EVENTS // ////////////////////////////////////////////////////////////// /// @dev is emitted when a new vault is added by the admin. event VaultAdded(uint256 indexed id, IERC4626 indexed vault); /// @dev is emitted when a payload is processed by the destination contract. event Processed( uint64 indexed srcChainID, uint64 indexed dstChainId, uint256 indexed srcPayloadId, uint256 amount, address vault ); /// @dev is emitted when an emergency withdrawal is processed event EmergencyWithdrawalProcessed(address indexed refundAddress, uint256 indexed amount); /// @dev is emitted when dust is forwarded to the paymaster event FormDustForwardedToPaymaster(address indexed token, uint256 indexed amount); ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @notice get Superform name of the ERC20 vault representation /// @return The ERC20 name function superformYieldTokenName() external view returns (string memory); /// @notice get Superform symbol of the ERC20 vault representation /// @return The ERC20 symbol function superformYieldTokenSymbol() external view returns (string memory); /// @notice get the state registry id associated with the vault function getStateRegistryId() external view returns (uint8); /// @notice Returns the vault address /// @return The address of the vault function getVaultAddress() external view returns (address); /// @notice Returns the vault address /// @return The address of the vault asset function getVaultAsset() external view returns (address); /// @notice Returns the name of the vault. /// @return The name of the vault function getVaultName() external view returns (string memory); /// @notice Returns the symbol of a vault. /// @return The symbol associated with a vault function getVaultSymbol() external view returns (string memory); /// @notice Returns the number of decimals in a vault for accounting purposes /// @return The number of decimals in the vault balance function getVaultDecimals() external view returns (uint256); /// @notice Returns the amount of underlying tokens each share of a vault is worth. /// @return The pricePerVaultShare value function getPricePerVaultShare() external view returns (uint256); /// @notice Returns the amount of vault shares owned by the form. /// @return The form's vault share balance function getVaultShareBalance() external view returns (uint256); /// @notice get the total amount of underlying managed in the ERC4626 vault function getTotalAssets() external view returns (uint256); /// @notice get the total amount of unredeemed vault shares in circulation function getTotalSupply() external view returns (uint256); /// @notice get the total amount of assets received if shares are actually redeemed /// @notice https://eips.ethereum.org/EIPS/eip-4626 function getPreviewPricePerVaultShare() external view returns (uint256); /// @dev API may need to know state of funds deployed function previewDepositTo(uint256 assets_) external view returns (uint256); /// @notice positionBalance() -> .vaultIds&destAmounts /// @return how much of an asset + interest (accrued) is to withdraw from the Vault function previewWithdrawFrom(uint256 assets_) external view returns (uint256); /// @dev API may need to know state of funds deployed function previewRedeemFrom(uint256 shares_) external view returns (uint256); ////////////////////////////////////////////////////////////// // EXTERNAL WRITE FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev process same chain id deposits /// @param singleVaultData_ A bytes representation containing all the data required to make a form action /// @param srcSender_ The address of the sender of the transaction /// @return shares The amount of vault shares received function directDepositIntoVault( InitSingleVaultData memory singleVaultData_, address srcSender_ ) external payable returns (uint256 shares); /// @dev process same chain id deposits /// @param singleVaultData_ A bytes representation containing all the data required to make a form action /// @param srcSender_ The address of the sender of the transaction /// @param srcChainId_ The chain id of the source chain /// @return shares The amount of vault shares received /// @dev is shares is `0` then no further action/acknowledgement needs to be sent function xChainDepositIntoVault( InitSingleVaultData memory singleVaultData_, address srcSender_, uint64 srcChainId_ ) external returns (uint256 shares); /// @dev process withdrawal of asset from a vault /// @param singleVaultData_ A bytes representation containing all the data required to make a form action /// @param srcSender_ The address of the sender of the transaction /// @return assets The amount of assets received function directWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address srcSender_ ) external returns (uint256 assets); /// @dev process withdrawal of asset from a vault /// @param singleVaultData_ A bytes representation containing all the data required to make a form action /// @param srcSender_ The address of the sender of the transaction /// @param srcChainId_ The chain id of the source chain /// @return assets The amount of assets received function xChainWithdrawFromVault( InitSingleVaultData memory singleVaultData_, address srcSender_, uint64 srcChainId_ ) external returns (uint256 assets); /// @dev process withdrawal of shares if form is paused /// @param receiverAddress_ The address to refund the shares to /// @param amount_ The amount of vault shares to refund function emergencyWithdraw(address receiverAddress_, uint256 amount_) external; /// @dev moves all dust in the contract to Paymaster contract /// @param token_ The address of the token to forward function forwardDustToPaymaster(address token_) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; /// @title ISuperRegistry /// @dev Interface for SuperRegistry /// @author Zeropoint Labs interface ISuperRegistry { ////////////////////////////////////////////////////////////// // EVENTS // ////////////////////////////////////////////////////////////// /// @dev emitted when permit2 is set. event SetPermit2(address indexed permit2); /// @dev is emitted when an address is set. event AddressUpdated( bytes32 indexed protocolAddressId, uint64 indexed chainId, address indexed oldAddress, address newAddress ); /// @dev is emitted when a new token bridge is configured. event SetBridgeAddress(uint256 indexed bridgeId, address indexed bridgeAddress); /// @dev is emitted when a new bridge validator is configured. event SetBridgeValidator(uint256 indexed bridgeId, address indexed bridgeValidator); /// @dev is emitted when a new amb is configured. event SetAmbAddress(uint8 indexed ambId_, address indexed ambAddress_, bool indexed isBroadcastAMB_); /// @dev is emitted when a new state registry is configured. event SetStateRegistryAddress(uint8 indexed registryId_, address indexed registryAddress_); /// @dev is emitted when a new delay is configured. event SetDelay(uint256 indexed oldDelay_, uint256 indexed newDelay_); /// @dev is emitted when a new vault limit is configured event SetVaultLimitPerDestination(uint64 indexed chainId_, uint256 indexed vaultLimit_); ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev gets the deposit rescue delay function delay() external view returns (uint256); /// @dev returns the permit2 address function PERMIT2() external view returns (address); /// @dev returns the id of the superform router module function SUPERFORM_ROUTER() external view returns (bytes32); /// @dev returns the id of the superform factory module function SUPERFORM_FACTORY() external view returns (bytes32); /// @dev returns the id of the superform paymaster contract function PAYMASTER() external view returns (bytes32); /// @dev returns the id of the superform payload helper contract function PAYMENT_HELPER() external view returns (bytes32); /// @dev returns the id of the core state registry module function CORE_STATE_REGISTRY() external view returns (bytes32); /// @dev returns the id of the timelock form state registry module function TIMELOCK_STATE_REGISTRY() external view returns (bytes32); /// @dev returns the id of the broadcast state registry module function BROADCAST_REGISTRY() external view returns (bytes32); /// @dev returns the id of the super positions module function SUPER_POSITIONS() external view returns (bytes32); /// @dev returns the id of the super rbac module function SUPER_RBAC() external view returns (bytes32); /// @dev returns the id of the payload helper module function PAYLOAD_HELPER() external view returns (bytes32); /// @dev returns the id of the dst swapper keeper function DST_SWAPPER() external view returns (bytes32); /// @dev returns the id of the emergency queue function EMERGENCY_QUEUE() external view returns (bytes32); /// @dev returns the id of the superform receiver function SUPERFORM_RECEIVER() external view returns (bytes32); /// @dev returns the id of the payment admin keeper function PAYMENT_ADMIN() external view returns (bytes32); /// @dev returns the id of the core state registry processor keeper function CORE_REGISTRY_PROCESSOR() external view returns (bytes32); /// @dev returns the id of the broadcast registry processor keeper function BROADCAST_REGISTRY_PROCESSOR() external view returns (bytes32); /// @dev returns the id of the timelock form state registry processor keeper function TIMELOCK_REGISTRY_PROCESSOR() external view returns (bytes32); /// @dev returns the id of the core state registry updater keeper function CORE_REGISTRY_UPDATER() external view returns (bytes32); /// @dev returns the id of the core state registry updater keeper function CORE_REGISTRY_RESCUER() external view returns (bytes32); /// @dev returns the id of the core state registry updater keeper function CORE_REGISTRY_DISPUTER() external view returns (bytes32); /// @dev returns the id of the core state registry updater keeper function DST_SWAPPER_PROCESSOR() external view returns (bytes32); /// @dev gets the address of a contract on current chain /// @param id_ is the id of the contract function getAddress(bytes32 id_) external view returns (address); /// @dev gets the address of a contract on a target chain /// @param id_ is the id of the contract /// @param chainId_ is the chain id of that chain function getAddressByChainId(bytes32 id_, uint64 chainId_) external view returns (address); /// @dev gets the address of a bridge /// @param bridgeId_ is the id of a bridge /// @return bridgeAddress_ is the address of the form function getBridgeAddress(uint8 bridgeId_) external view returns (address bridgeAddress_); /// @dev gets the address of a bridge validator /// @param bridgeId_ is the id of a bridge /// @return bridgeValidator_ is the address of the form function getBridgeValidator(uint8 bridgeId_) external view returns (address bridgeValidator_); /// @dev gets the address of a amb /// @param ambId_ is the id of a bridge /// @return ambAddress_ is the address of the form function getAmbAddress(uint8 ambId_) external view returns (address ambAddress_); /// @dev gets the id of the amb /// @param ambAddress_ is the address of an amb /// @return ambId_ is the identifier of an amb function getAmbId(address ambAddress_) external view returns (uint8 ambId_); /// @dev gets the address of the registry /// @param registryId_ is the id of the state registry /// @return registryAddress_ is the address of the state registry function getStateRegistry(uint8 registryId_) external view returns (address registryAddress_); /// @dev gets the id of the registry /// @notice reverts if the id is not found /// @param registryAddress_ is the address of the state registry /// @return registryId_ is the id of the state registry function getStateRegistryId(address registryAddress_) external view returns (uint8 registryId_); /// @dev gets the safe vault limit /// @param chainId_ is the id of the remote chain /// @return vaultLimitPerDestination_ is the safe number of vaults to deposit /// without hitting out of gas error function getVaultLimitPerDestination(uint64 chainId_) external view returns (uint256 vaultLimitPerDestination_); /// @dev helps validate if an address is a valid state registry /// @param registryAddress_ is the address of the state registry /// @return valid_ a flag indicating if its valid. function isValidStateRegistry(address registryAddress_) external view returns (bool valid_); /// @dev helps validate if an address is a valid amb implementation /// @param ambAddress_ is the address of the amb implementation /// @return valid_ a flag indicating if its valid. function isValidAmbImpl(address ambAddress_) external view returns (bool valid_); /// @dev helps validate if an address is a valid broadcast amb implementation /// @param ambAddress_ is the address of the broadcast amb implementation /// @return valid_ a flag indicating if its valid. function isValidBroadcastAmbImpl(address ambAddress_) external view returns (bool valid_); ////////////////////////////////////////////////////////////// // EXTERNAL WRITE FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev sets the deposit rescue delay /// @param delay_ the delay in seconds before the deposit rescue can be finalized function setDelay(uint256 delay_) external; /// @dev sets the permit2 address /// @param permit2_ the address of the permit2 contract function setPermit2(address permit2_) external; /// @dev sets the safe vault limit /// @param chainId_ is the remote chain identifier /// @param vaultLimit_ is the max limit of vaults per transaction function setVaultLimitPerDestination(uint64 chainId_, uint256 vaultLimit_) external; /// @dev sets new addresses on specific chains. /// @param ids_ are the identifiers of the address on that chain /// @param newAddresses_ are the new addresses on that chain /// @param chainIds_ are the chain ids of that chain function batchSetAddress( bytes32[] calldata ids_, address[] calldata newAddresses_, uint64[] calldata chainIds_ ) external; /// @dev sets a new address on a specific chain. /// @param id_ the identifier of the address on that chain /// @param newAddress_ the new address on that chain /// @param chainId_ the chain id of that chain function setAddress(bytes32 id_, address newAddress_, uint64 chainId_) external; /// @dev allows admin to set the bridge address for an bridge id. /// @notice this function operates in an APPEND-ONLY fashion. /// @param bridgeId_ represents the bridge unique identifier. /// @param bridgeAddress_ represents the bridge address. /// @param bridgeValidator_ represents the bridge validator address. function setBridgeAddresses( uint8[] memory bridgeId_, address[] memory bridgeAddress_, address[] memory bridgeValidator_ ) external; /// @dev allows admin to set the amb address for an amb id. /// @notice this function operates in an APPEND-ONLY fashion. /// @param ambId_ represents the bridge unique identifier. /// @param ambAddress_ represents the bridge address. /// @param isBroadcastAMB_ represents whether the amb implementation supports broadcasting function setAmbAddress( uint8[] memory ambId_, address[] memory ambAddress_, bool[] memory isBroadcastAMB_ ) external; /// @dev allows admin to set the state registry address for an state registry id. /// @notice this function operates in an APPEND-ONLY fashion. /// @param registryId_ represents the state registry's unique identifier. /// @param registryAddress_ represents the state registry's address. function setStateRegistryAddress(uint8[] memory registryId_, address[] memory registryAddress_) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; /// @title ISuperformFactory /// @dev Interface for SuperformFactory /// @author ZeroPoint Labs interface ISuperformFactory { ////////////////////////////////////////////////////////////// // CONSTANTS // ////////////////////////////////////////////////////////////// enum PauseStatus { NON_PAUSED, PAUSED } ////////////////////////////////////////////////////////////// // EVENTS // ////////////////////////////////////////////////////////////// /// @dev emitted when a new formImplementation is entered into the factory /// @param formImplementation is the address of the new form implementation /// @param formImplementationId is the id of the formImplementation /// @param formStateRegistryId is any additional state registry id of the formImplementation event FormImplementationAdded( address indexed formImplementation, uint256 indexed formImplementationId, uint8 indexed formStateRegistryId ); /// @dev emitted when a new Superform is created /// @param formImplementationId is the id of the form implementation /// @param vault is the address of the vault /// @param superformId is the id of the superform /// @param superform is the address of the superform event SuperformCreated( uint256 indexed formImplementationId, address indexed vault, uint256 indexed superformId, address superform ); /// @dev emitted when a new SuperRegistry is set /// @param superRegistry is the address of the super registry event SuperRegistrySet(address indexed superRegistry); /// @dev emitted when a form implementation is paused /// @param formImplementationId is the id of the form implementation /// @param paused is the new paused status event FormImplementationPaused(uint256 indexed formImplementationId, PauseStatus indexed paused); ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev returns the number of forms /// @return forms_ is the number of forms function getFormCount() external view returns (uint256 forms_); /// @dev returns the number of superforms /// @return superforms_ is the number of superforms function getSuperformCount() external view returns (uint256 superforms_); /// @dev returns the address of a form implementation /// @param formImplementationId_ is the id of the form implementation /// @return formImplementation_ is the address of the form implementation function getFormImplementation(uint32 formImplementationId_) external view returns (address formImplementation_); /// @dev returns the form state registry id of a form implementation /// @param formImplementationId_ is the id of the form implementation /// @return stateRegistryId_ is the additional state registry id of the form function getFormStateRegistryId(uint32 formImplementationId_) external view returns (uint8 stateRegistryId_); /// @dev returns the paused status of form implementation /// @param formImplementationId_ is the id of the form implementation /// @return paused_ is the current paused status of the form formImplementationId_ function isFormImplementationPaused(uint32 formImplementationId_) external view returns (bool paused_); /// @dev returns the address of a superform /// @param superformId_ is the id of the superform /// @return superform_ is the address of the superform /// @return formImplementationId_ is the id of the form implementation /// @return chainId_ is the chain id function getSuperform(uint256 superformId_) external pure returns (address superform_, uint32 formImplementationId_, uint64 chainId_); /// @dev returns if an address has been added to a Form /// @param superformId_ is the id of the superform /// @return isSuperform_ bool if it exists function isSuperform(uint256 superformId_) external view returns (bool isSuperform_); /// @dev Reverse query of getSuperform, returns all superforms for a given vault /// @param vault_ is the address of a vault /// @return superformIds_ is the id of the superform /// @return superforms_ is the address of the superform function getAllSuperformsFromVault(address vault_) external view returns (uint256[] memory superformIds_, address[] memory superforms_); ////////////////////////////////////////////////////////////// // EXTERNAL WRITE FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev allows an admin to add a Form implementation to the factory /// @param formImplementation_ is the address of a form implementation /// @param formImplementationId_ is the id of the form implementation (generated off-chain and equal in all chains) /// @param formStateRegistryId_ is the id of any additional state registry for that form /// @dev formStateRegistryId_ 1 is default for all form implementations, pass in formStateRegistryId_ only if an /// additional state registry is required function addFormImplementation( address formImplementation_, uint32 formImplementationId_, uint8 formStateRegistryId_ ) external; /// @dev To add new vaults to Form implementations, fusing them together into Superforms /// @param formImplementationId_ is the form implementation we want to attach the vault to /// @param vault_ is the address of the vault /// @return superformId_ is the id of the created superform /// @return superform_ is the address of the created superform function createSuperform( uint32 formImplementationId_, address vault_ ) external returns (uint256 superformId_, address superform_); /// @dev to synchronize superforms added to different chains using broadcast registry /// @param data_ is the cross-chain superform id function stateSyncBroadcast(bytes memory data_) external payable; /// @dev allows an admin to change the status of a form /// @param formImplementationId_ is the id of the form implementation /// @param status_ is the new status /// @param extraData_ is optional & passed when broadcasting of status is needed function changeFormImplementationPauseStatus( uint32 formImplementationId_, PauseStatus status_, bytes memory extraData_ ) external payable; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import { InitSingleVaultData } from "src/types/DataTypes.sol"; /// @title IEmergencyQueue /// @dev Interface for EmergencyQueue /// @author ZeroPoint Labs interface IEmergencyQueue { ////////////////////////////////////////////////////////////// // EVENTS // ////////////////////////////////////////////////////////////// event WithdrawalQueued( address indexed receiverAddress, uint256 indexed id, uint256 indexed superformId, uint256 amount, uint256 srcPayloadId ); event WithdrawalProcessed( address indexed refundAddress, uint256 indexed id, uint256 indexed superformId, uint256 amount ); ////////////////////////////////////////////////////////////// // EXTERNAL VIEW FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev returns the execution status of an id in the emergency queue /// @param id is the identifier of the queued action /// @return boolean representing the execution status function queuedWithdrawalStatus(uint256 id) external view returns (bool); ////////////////////////////////////////////////////////////// // EXTERNAL WRITE FUNCTIONS // ////////////////////////////////////////////////////////////// /// @dev called by paused forms to queue up withdrawals for exit /// @param data_ is the single vault data passed by the user function queueWithdrawal(InitSingleVaultData memory data_) external; /// @dev called by emergency admin to processed queued withdrawal /// @param id_ is the identifier of the queued action function executeQueuedWithdrawal(uint256 id_) external; /// @dev called by emergency admin to batch process queued withdrawals /// @param ids_ is the array of identifiers of the queued actions function batchExecuteQueuedWithdrawal(uint256[] memory ids_) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 standard as defined in the ERC. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612]. * * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
{ "remappings": [ "solmate/=lib/ERC1155A/lib/solmate/src/", "ERC1155A/=lib/ERC1155A/src/", "@openzeppelin/contracts/=lib/ERC1155A/lib/openzeppelin-contracts/contracts/", "ds-test/=lib/ds-test/src/", "erc4626-tests/=lib/ERC1155A/lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/ERC1155A/lib/openzeppelin-contracts/", "pigeon/=lib/pigeon/src/", "solady/=lib/pigeon/lib/solady/", "super-vaults/=lib/super-vaults/src/", "v2-core/=lib/super-vaults/lib/v2-core/contracts/", "v2-periphery/=lib/super-vaults/lib/v2-periphery/contracts/", "v3-core/=lib/super-vaults/lib/v3-core/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
[{"inputs":[{"internalType":"address","name":"superRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"BLOCK_CHAIN_ID_OUT_OF_BOUNDS","type":"error"},{"inputs":[],"name":"CANNOT_FORWARD_4646_TOKEN","type":"error"},{"inputs":[],"name":"DIFFERENT_TOKENS","type":"error"},{"inputs":[],"name":"DIRECT_DEPOSIT_SWAP_FAILED","type":"error"},{"inputs":[],"name":"DIRECT_WITHDRAW_INVALID_LIQ_REQUEST","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"FAILED_TO_EXECUTE_TXDATA","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"INSUFFICIENT_ALLOWANCE_FOR_DEPOSIT","type":"error"},{"inputs":[],"name":"INSUFFICIENT_BALANCE","type":"error"},{"inputs":[],"name":"INSUFFICIENT_NATIVE_AMOUNT","type":"error"},{"inputs":[],"name":"INVALID_CHAIN_ID","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NOT_CORE_STATE_REGISTRY","type":"error"},{"inputs":[],"name":"NOT_EMERGENCY_QUEUE","type":"error"},{"inputs":[],"name":"NOT_SUPERFORM_ROUTER","type":"error"},{"inputs":[],"name":"NOT_SUPER_REGISTRY","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"PAUSED","type":"error"},{"inputs":[],"name":"SUPERFORM_ID_NONEXISTENT","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"VAULT_IMPLEMENTATION_FAILED","type":"error"},{"inputs":[],"name":"WITHDRAW_TOKEN_NOT_UPDATED","type":"error"},{"inputs":[],"name":"WITHDRAW_TX_DATA_NOT_UPDATED","type":"error"},{"inputs":[],"name":"WITHDRAW_ZERO_COLLATERAL","type":"error"},{"inputs":[],"name":"XCHAIN_WITHDRAW_INVALID_LIQ_REQUEST","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"inputs":[],"name":"ZERO_AMOUNT","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"refundAddress","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawalProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FormDustForwardedToPaymaster","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"srcChainID","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"dstChainId","type":"uint64"},{"indexed":true,"internalType":"uint256","name":"srcPayloadId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"}],"name":"Processed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"contract IERC4626","name":"vault","type":"address"}],"name":"VaultAdded","type":"event"},{"inputs":[],"name":"CHAIN_ID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"payloadId","type":"uint256"},{"internalType":"uint256","name":"superformId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"maxSlippage","type":"uint256"},{"components":[{"internalType":"bytes","name":"txData","type":"bytes"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"interimToken","type":"address"},{"internalType":"uint8","name":"bridgeId","type":"uint8"},{"internalType":"uint64","name":"liqDstChainId","type":"uint64"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"internalType":"struct LiqRequest","name":"liqData","type":"tuple"},{"internalType":"bool","name":"hasDstSwap","type":"bool"},{"internalType":"bool","name":"retain4626","type":"bool"},{"internalType":"address","name":"receiverAddress","type":"address"},{"internalType":"bytes","name":"extraFormData","type":"bytes"}],"internalType":"struct InitSingleVaultData","name":"singleVaultData_","type":"tuple"},{"internalType":"address","name":"srcSender_","type":"address"}],"name":"directDepositIntoVault","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"payloadId","type":"uint256"},{"internalType":"uint256","name":"superformId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"maxSlippage","type":"uint256"},{"components":[{"internalType":"bytes","name":"txData","type":"bytes"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"interimToken","type":"address"},{"internalType":"uint8","name":"bridgeId","type":"uint8"},{"internalType":"uint64","name":"liqDstChainId","type":"uint64"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"internalType":"struct LiqRequest","name":"liqData","type":"tuple"},{"internalType":"bool","name":"hasDstSwap","type":"bool"},{"internalType":"bool","name":"retain4626","type":"bool"},{"internalType":"address","name":"receiverAddress","type":"address"},{"internalType":"bytes","name":"extraFormData","type":"bytes"}],"internalType":"struct InitSingleVaultData","name":"singleVaultData_","type":"tuple"},{"internalType":"address","name":"srcSender_","type":"address"}],"name":"directWithdrawFromVault","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiverAddress_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token_","type":"address"}],"name":"forwardDustToPaymaster","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getPreviewPricePerVaultShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPricePerVaultShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStateRegistryId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultShareBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVaultSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"superRegistry_","type":"address"},{"internalType":"address","name":"vault_","type":"address"},{"internalType":"address","name":"asset_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets_","type":"uint256"}],"name":"previewDepositTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"name":"previewRedeemFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets_","type":"uint256"}],"name":"previewWithdrawFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"superRegistry","outputs":[{"internalType":"contract ISuperRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"superformYieldTokenName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"superformYieldTokenSymbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId_","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"payloadId","type":"uint256"},{"internalType":"uint256","name":"superformId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"maxSlippage","type":"uint256"},{"components":[{"internalType":"bytes","name":"txData","type":"bytes"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"interimToken","type":"address"},{"internalType":"uint8","name":"bridgeId","type":"uint8"},{"internalType":"uint64","name":"liqDstChainId","type":"uint64"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"internalType":"struct LiqRequest","name":"liqData","type":"tuple"},{"internalType":"bool","name":"hasDstSwap","type":"bool"},{"internalType":"bool","name":"retain4626","type":"bool"},{"internalType":"address","name":"receiverAddress","type":"address"},{"internalType":"bytes","name":"extraFormData","type":"bytes"}],"internalType":"struct InitSingleVaultData","name":"singleVaultData_","type":"tuple"},{"internalType":"address","name":"srcSender_","type":"address"},{"internalType":"uint64","name":"srcChainId_","type":"uint64"}],"name":"xChainDepositIntoVault","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"payloadId","type":"uint256"},{"internalType":"uint256","name":"superformId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"outputAmount","type":"uint256"},{"internalType":"uint256","name":"maxSlippage","type":"uint256"},{"components":[{"internalType":"bytes","name":"txData","type":"bytes"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"interimToken","type":"address"},{"internalType":"uint8","name":"bridgeId","type":"uint8"},{"internalType":"uint64","name":"liqDstChainId","type":"uint64"},{"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"internalType":"struct LiqRequest","name":"liqData","type":"tuple"},{"internalType":"bool","name":"hasDstSwap","type":"bool"},{"internalType":"bool","name":"retain4626","type":"bool"},{"internalType":"address","name":"receiverAddress","type":"address"},{"internalType":"bytes","name":"extraFormData","type":"bytes"}],"internalType":"struct InitSingleVaultData","name":"singleVaultData_","type":"tuple"},{"internalType":"address","name":"srcSender_","type":"address"},{"internalType":"uint64","name":"srcChainId_","type":"uint64"}],"name":"xChainWithdrawFromVault","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.