// 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();
}
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import { IERC5115To4626Wrapper } from "../interfaces/IERC5115To4626Wrapper.sol";
import { IStandardizedYield } from "src/vendor/pendle/IStandardizedYield.sol";
import { IERC20Metadata, IERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Error } from "src/libraries/Error.sol";
/// @title ERC5115To4626Wrapper
/// @dev Wrapper contract for ERC5115 to ERC4626 conversion
/// @author Zeropoint Labs
contract ERC5115To4626Wrapper is IERC5115To4626Wrapper {
using SafeERC20 for IERC20;
//////////////////////////////////////////////////////////////
// ERRORS //
//////////////////////////////////////////////////////////////
/// @dev Emitted when the receiver is this contract
error INVALID_RECEIVER();
/// @dev Emitted when the tokenIn is not valid
error INVALID_TOKEN_IN();
/// @dev Emitted when the tokenOut is not valid
error INVALID_TOKEN_OUT();
//////////////////////////////////////////////////////////////
// STORAGE //
//////////////////////////////////////////////////////////////
/// @dev The address of the underlying ERC5115 vault
address public immutable vault;
/// @dev The address of the token used for deposits
address public immutable asset;
/// @dev The address of the token used for withdrawals
address public immutable mainTokenOut;
//////////////////////////////////////////////////////////////
// CONSTRUCTOR //
//////////////////////////////////////////////////////////////
/// @notice Initializes the wrapper contract
/// @param vault_ The address of the ERC5115 vault
/// @param tokenIn_ The address of the token used for deposits
/// @param tokenOut_ The address of the token used for withdrawals
constructor(address vault_, address tokenIn_, address tokenOut_) {
if (vault_ == address(0) || tokenIn_ == address(0) || tokenOut_ == address(0)) revert Error.ZERO_ADDRESS();
_validateTokenIn(tokenIn_, vault_);
_validateTokenOut(tokenOut_, vault_);
vault = vault_;
asset = tokenIn_;
mainTokenOut = tokenOut_;
}
//////////////////////////////////////////////////////////////
// EXTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @inheritdoc IERC5115To4626Wrapper
function deposit(
address receiver,
uint256 amountTokenToDeposit,
uint256 minSharesOut
)
external
returns (uint256 amountSharesOut)
{
address tokenIn = asset;
if (receiver == address(this)) revert INVALID_RECEIVER();
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountTokenToDeposit);
IERC20(tokenIn).safeIncreaseAllowance(vault, amountTokenToDeposit);
amountSharesOut = IStandardizedYield(vault).deposit(receiver, tokenIn, amountTokenToDeposit, minSharesOut);
if (IERC20(tokenIn).allowance(address(this), vault) > 0) IERC20(tokenIn).forceApprove(vault, 0);
}
/// @inheritdoc IERC5115To4626Wrapper
function redeem(
address receiver,
uint256 amountSharesToRedeem,
uint256 minTokenOut
)
external
returns (uint256 amountTokenOut)
{
if (receiver == address(this)) revert INVALID_RECEIVER();
IERC20(vault).safeTransferFrom(msg.sender, address(this), amountSharesToRedeem);
return IStandardizedYield(vault).redeem(receiver, amountSharesToRedeem, mainTokenOut, minTokenOut, false);
}
/// @inheritdoc IERC5115To4626Wrapper
function claimRewards(address user) external returns (uint256[] memory rewardAmounts) {
return IStandardizedYield(vault).claimRewards(user);
}
//////////////////////////////////////////////////////////////
// EXTERNAL VIEW FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @inheritdoc IERC5115To4626Wrapper
function getUnderlying5115Vault() external view returns (address) {
return vault;
}
/// @inheritdoc IERC5115To4626Wrapper
function getMainTokenIn() external view returns (address) {
return asset;
}
/// @inheritdoc IERC5115To4626Wrapper
function getMainTokenOut() external view returns (address) {
return mainTokenOut;
}
/// @inheritdoc IERC5115To4626Wrapper
function exchangeRate() external view returns (uint256 res) {
return IStandardizedYield(vault).exchangeRate();
}
/// @inheritdoc IERC5115To4626Wrapper
function accruedRewards(address user) external view returns (uint256[] memory rewardAmounts) {
return IStandardizedYield(vault).accruedRewards(user);
}
/// @inheritdoc IERC5115To4626Wrapper
function rewardIndexesCurrent() external returns (uint256[] memory indexes) {
return IStandardizedYield(vault).rewardIndexesCurrent();
}
/// @inheritdoc IERC5115To4626Wrapper
function rewardIndexesStored() external view returns (uint256[] memory indexes) {
return IStandardizedYield(vault).rewardIndexesStored();
}
/// @inheritdoc IERC5115To4626Wrapper
function getRewardTokens() external view returns (address[] memory) {
return IStandardizedYield(vault).getRewardTokens();
}
/// @inheritdoc IERC5115To4626Wrapper
function yieldToken() external view returns (address) {
return IStandardizedYield(vault).yieldToken();
}
/// @inheritdoc IERC5115To4626Wrapper
function getTokensIn() external view returns (address[] memory res) {
return IStandardizedYield(vault).getTokensIn();
}
/// @inheritdoc IERC5115To4626Wrapper
function getTokensOut() external view returns (address[] memory res) {
return IStandardizedYield(vault).getTokensOut();
}
/// @inheritdoc IERC5115To4626Wrapper
function isValidTokenIn(address token) public view returns (bool) {
return IStandardizedYield(vault).isValidTokenIn(token);
}
/// @inheritdoc IERC5115To4626Wrapper
function isValidTokenOut(address token) public view returns (bool) {
return IStandardizedYield(vault).isValidTokenOut(token);
}
/// @inheritdoc IERC5115To4626Wrapper
function previewDeposit(
address tokenIn,
uint256 amountTokenToDeposit
)
external
view
returns (uint256 amountSharesOut)
{
return IStandardizedYield(vault).previewDeposit(tokenIn, amountTokenToDeposit);
}
/// @inheritdoc IERC5115To4626Wrapper
function previewRedeem(
address tokenOut,
uint256 amountSharesToRedeem
)
external
view
returns (uint256 amountTokenOut)
{
return IStandardizedYield(vault).previewRedeem(tokenOut, amountSharesToRedeem);
}
/// @inheritdoc IERC5115To4626Wrapper
function assetInfo()
external
view
returns (IStandardizedYield.AssetType assetType, address assetAddress, uint8 assetDecimals)
{
return IStandardizedYield(vault).assetInfo();
}
/// @notice Returns the allowance of the wrapped 5115 vault token
/// @param owner The address of the account owning vault tokens
/// @param spender The address of the account able to transfer the tokens
/// @return The number of remaining tokens allowed to spent
function allowance(address owner, address spender) external view returns (uint256) {
return IStandardizedYield(vault).allowance(owner, spender);
}
/// @notice Returns the balance of the wrapped 5115 vault token
/// @param account The address of the account to query
/// @return The amount of tokens owned by the account
function balanceOf(address account) external view returns (uint256) {
return IStandardizedYield(vault).balanceOf(account);
}
/// @notice Returns the decimals of the wrapped 5115 vault token
/// @return The number of decimals
function decimals() external view returns (uint8) {
return IStandardizedYield(vault).decimals();
}
/// @notice Returns the name of the wrapped 5115 vault token
/// @return The name of the token
function name() external view returns (string memory) {
return IStandardizedYield(vault).name();
}
/// @notice Returns the symbol of the wrapped 5115 vault token
/// @return The symbol of the token
function symbol() external view returns (string memory) {
return IStandardizedYield(vault).symbol();
}
/// @notice Returns the total token supply of the wrapped 5115 vault token
/// @return The total supply of tokens
function totalSupply() external view returns (uint256) {
return IStandardizedYield(vault).totalSupply();
}
/// @notice Not implemented, reverts when called
function approve(address, uint256) external pure returns (bool) {
revert Error.NOT_IMPLEMENTED();
}
/// @notice Not implemented, reverts when called
function transfer(address, uint256) external pure returns (bool) {
revert Error.NOT_IMPLEMENTED();
}
/// @notice Not implemented, reverts when called
function transferFrom(address, address, uint256) external pure returns (bool) {
revert Error.NOT_IMPLEMENTED();
}
//////////////////////////////////////////////////////////////
// INTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @dev Validates if the given token is a valid input token for the vault
/// @param token_ The address of the token to validate
/// @param vault_ The address of the vault
function _validateTokenIn(address token_, address vault_) internal view {
try IStandardizedYield(vault_).isValidTokenIn(token_) returns (bool isValid) {
if (!isValid) {
revert INVALID_TOKEN_IN();
}
} catch {
address[] memory tokensIn = IStandardizedYield(vault_).getTokensIn();
bool found;
for (uint256 i = 0; i < tokensIn.length; i++) {
if (tokensIn[i] == token_) {
found = true;
break;
}
}
if (!found) {
revert INVALID_TOKEN_IN();
}
}
}
/// @dev Validates if the given token is a valid output token for the vault
/// @param token_ The address of the token to validate
/// @param vault_ The address of the vault
function _validateTokenOut(address token_, address vault_) internal view {
try IStandardizedYield(vault_).isValidTokenOut(token_) returns (bool isValid) {
if (!isValid) {
revert INVALID_TOKEN_OUT();
}
} catch {
address[] memory tokensOut = IStandardizedYield(vault_).getTokensOut();
bool found;
for (uint256 i = 0; i < tokensOut.length; i++) {
if (tokensOut[i] == token_) {
found = true;
break;
}
}
if (!found) {
revert INVALID_TOKEN_OUT();
}
}
}
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import { IERC5115To4626WrapperFactory, WrapperMetadata } from "../interfaces/IERC5115To4626WrapperFactory.sol";
import "./ERC5115To4626Wrapper.sol";
import { ISuperRBAC } from "src/interfaces/ISuperRBAC.sol";
import { Error } from "src/libraries/Error.sol";
import { ISuperRegistry } from "src/interfaces/ISuperRegistry.sol";
import { ISuperformFactory } from "src/interfaces/ISuperformFactory.sol";
contract ERC5115To4626WrapperFactory is IERC5115To4626WrapperFactory {
//////////////////////////////////////////////////////////////
// CONSTANTS //
//////////////////////////////////////////////////////////////
ISuperRegistry public immutable superRegistry;
uint64 public immutable CHAIN_ID;
//////////////////////////////////////////////////////////////
// STATE VARIABLES //
//////////////////////////////////////////////////////////////
mapping(bytes32 wrapperKey => WrapperMetadata metadata) public wrappers;
//////////////////////////////////////////////////////////////
// MODIFIERS //
//////////////////////////////////////////////////////////////
modifier onlyEmergencyAdmin() {
if (!ISuperRBAC(superRegistry.getAddress(keccak256("SUPER_RBAC"))).hasEmergencyAdminRole(msg.sender)) {
revert Error.NOT_EMERGENCY_ADMIN();
}
_;
}
//////////////////////////////////////////////////////////////
// CONSTRUCTOR //
//////////////////////////////////////////////////////////////
/// @param superRegistry_ the superform registry contract
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_);
}
//////////////////////////////////////////////////////////////
// EXTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @inheritdoc IERC5115To4626WrapperFactory
function createWrapper(
address underlyingVaultAddress_,
address tokenIn_,
address tokenOut_
)
external
override
returns (address wrapper)
{
bytes32 wrapperKey = keccak256(abi.encodePacked(underlyingVaultAddress_, tokenIn_, tokenOut_));
WrapperMetadata storage metadata = wrappers[wrapperKey];
if (metadata.wrapper != address(0)) revert WRAPPER_ALREADY_EXISTS();
wrapper = address(new ERC5115To4626Wrapper(underlyingVaultAddress_, tokenIn_, tokenOut_));
metadata.formImplementation = address(0);
metadata.underlyingVaultAddress = underlyingVaultAddress_;
metadata.tokenIn = tokenIn_;
metadata.tokenOut = tokenOut_;
metadata.wrapper = wrapper;
emit WrapperCreated(wrapper, wrapperKey);
}
/// @inheritdoc IERC5115To4626WrapperFactory
function createWrapperWithSuperform(
uint32 formImplementationId_,
address underlyingVaultAddress_,
address tokenIn_,
address tokenOut_
)
external
override
returns (address wrapper)
{
wrapper = _createWrapperWithSuperform(formImplementationId_, underlyingVaultAddress_, tokenIn_, tokenOut_);
}
/// @inheritdoc IERC5115To4626WrapperFactory
function batchCreateWrappersWithSuperform(
uint32[] calldata formImplementationIds_,
address[] calldata underlyingVaultAddresses,
address[] calldata tokenIns,
address[] calldata tokenOuts
)
external
override
returns (address[] memory wrappers_)
{
uint256 len = underlyingVaultAddresses.length;
if (
len != tokenIns.length || tokenIns.length != tokenOuts.length
|| tokenOuts.length != formImplementationIds_.length
) {
revert Error.ARRAY_LENGTH_MISMATCH();
}
wrappers_ = new address[](len);
for (uint256 i; i < len; i++) {
wrappers_[i] = _createWrapperWithSuperform(
formImplementationIds_[i], underlyingVaultAddresses[i], tokenIns[i], tokenOuts[i]
);
}
}
/// @inheritdoc IERC5115To4626WrapperFactory
function createSuperformForWrapper(
bytes32 wrapperKey,
uint32 formImplementationId_
)
external
override
returns (uint256 superformId, address superform)
{
WrapperMetadata storage metadata = wrappers[wrapperKey];
if (metadata.wrapper == address(0)) revert WRAPPER_DOES_NOT_EXIST();
ISuperformFactory sf = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
address formImplementation = sf.getFormImplementation(formImplementationId_);
if (formImplementation == address(0)) revert Error.FORM_DOES_NOT_EXIST();
if (metadata.formImplementation != address(0)) revert WRAPPER_ALREADY_HAS_FORM();
metadata.formImplementation = formImplementation;
(superformId, superform) = sf.createSuperform(formImplementationId_, metadata.wrapper);
emit CreatedSuperformForExistingWrapper(metadata.wrapper, wrapperKey, superformId, superform);
}
/// @inheritdoc IERC5115To4626WrapperFactory
function batchUpdateWrapperFormImplementation(
bytes32[] calldata wrapperKeys,
uint32[] calldata formImplementationIds
)
external
override
onlyEmergencyAdmin
{
if (wrapperKeys.length != formImplementationIds.length) revert Error.ARRAY_LENGTH_MISMATCH();
ISuperformFactory sf = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
address newFormImpl;
for (uint256 i = 0; i < wrapperKeys.length; i++) {
WrapperMetadata storage metadata = wrappers[wrapperKeys[i]];
if (metadata.formImplementation == address(0)) revert WRAPPER_DOES_NOT_EXIST();
newFormImpl = sf.getFormImplementation(formImplementationIds[i]);
if (newFormImpl == address(0)) revert Error.FORM_DOES_NOT_EXIST();
metadata.formImplementation = newFormImpl;
emit WrapperUpdatedWithImplementation(metadata.wrapper, wrapperKeys[i], newFormImpl);
}
}
//////////////////////////////////////////////////////////////
// INTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////
function _createWrapperWithSuperform(
uint32 formImplementationId_,
address underlyingVaultAddress_,
address tokenIn_,
address tokenOut_
)
internal
returns (address wrapper)
{
bytes32 wrapperKey = keccak256(abi.encodePacked(underlyingVaultAddress_, tokenIn_, tokenOut_));
WrapperMetadata storage metadata = wrappers[wrapperKey];
if (metadata.wrapper != address(0)) revert WRAPPER_ALREADY_EXISTS();
ISuperformFactory sf = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
address formImplementation = sf.getFormImplementation(formImplementationId_);
if (formImplementation == address(0)) revert Error.FORM_DOES_NOT_EXIST();
wrapper = address(new ERC5115To4626Wrapper(underlyingVaultAddress_, tokenIn_, tokenOut_));
metadata.formImplementation = formImplementation;
metadata.underlyingVaultAddress = underlyingVaultAddress_;
metadata.tokenIn = tokenIn_;
metadata.tokenOut = tokenOut_;
metadata.wrapper = wrapper;
(uint256 superformId, address superform) = sf.createSuperform(formImplementationId_, wrapper);
emit WrapperCreatedWithSuperform(wrapper, wrapperKey, superformId, superform);
}
}
// 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}
// 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/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/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: BUSL-1.1
pragma solidity ^0.8.23;
import { IStandardizedYield } from "src/vendor/pendle/IStandardizedYield.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
/// @title IERC5115To4626Wrapper
/// @dev Interface for ERC5115To4626Wrapper
/// @author Zeropoint Labs
interface IERC5115To4626Wrapper is IERC20Metadata {
//////////////////////////////////////////////////////////////
// EXTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @notice Deposits tokens and mints shares
/// @param receiver The address that will receive the minted shares
/// @param amountTokenToDeposit The amount of tokens to deposit
/// @param minSharesOut The minimum amount of shares that must be minted for the transaction to be successful
/// @return amountSharesOut The actual amount of shares minted
function deposit(
address receiver,
uint256 amountTokenToDeposit,
uint256 minSharesOut
)
external
returns (uint256 amountSharesOut);
/// @notice Redeems shares for tokens
/// @param receiver The address that will receive the redeemed tokens
/// @param amountSharesToRedeem The amount of shares to redeem
/// @param minTokenOut The minimum amount of tokens that must be received for the transaction to be successful
/// @return amountTokenOut The actual amount of tokens received
function redeem(
address receiver,
uint256 amountSharesToRedeem,
uint256 minTokenOut
)
external
returns (uint256 amountTokenOut);
/// @notice Claims rewards for a user
/// @param user The user receiving their rewards
/// @return rewardAmounts An array of reward amounts in the same order as `getRewardTokens`
function claimRewards(address user) external returns (uint256[] memory rewardAmounts);
//////////////////////////////////////////////////////////////
// EXTERNAL VIEW FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @notice Returns the 5115 vault wrapped
/// @return The address of the underlying 5115 vault
function getUnderlying5115Vault() external view returns (address);
/// @notice Returns the token used for deposits to the underlying 5115
/// @return The address of the main token in
function getMainTokenIn() external view returns (address);
/// @notice Returns the token used for redemptions
/// @return The address of the main token out
function getMainTokenOut() external view returns (address);
/// @notice Returns the current exchange rate
/// @dev exchangeRate * syBalance / 1e18 must return the asset balance of the account
/// @return res The current exchange rate
function exchangeRate() external view returns (uint256 res);
/// @notice Returns the amount of unclaimed rewards for a user
/// @param user The user to check for
/// @return rewardAmounts An array of reward amounts in the same order as `getRewardTokens`
function accruedRewards(address user) external view returns (uint256[] memory rewardAmounts);
/// @notice Returns the current reward indexes
/// @return indexes The current reward indexes
function rewardIndexesCurrent() external returns (uint256[] memory indexes);
/// @notice Returns the stored reward indexes
/// @return indexes The stored reward indexes
function rewardIndexesStored() external view returns (uint256[] memory indexes);
/// @notice Returns the list of reward token addresses
/// @return The addresses of reward tokens
function getRewardTokens() external view returns (address[] memory);
/// @notice Returns the address of the underlying yield token
/// @return The address of the yield token
function yieldToken() external view returns (address);
/// @notice Returns all tokens that can mint this SY
/// @return res The addresses of tokens that can be used for minting
function getTokensIn() external view returns (address[] memory res);
/// @notice Returns all tokens that can be redeemed by this SY
/// @return res The addresses of tokens that can be redeemed
function getTokensOut() external view returns (address[] memory res);
/// @notice Checks if a token is valid for deposit
/// @param token The address of the token to check
/// @return True if the token is valid for deposit, false otherwise
function isValidTokenIn(address token) external view returns (bool);
/// @notice Checks if a token is valid for redemption
/// @param token The address of the token to check
/// @return True if the token is valid for redemption, false otherwise
function isValidTokenOut(address token) external view returns (bool);
/// @notice Previews the amount of shares received for a deposit
/// @param tokenIn The address of the token to deposit
/// @param amountTokenToDeposit The amount of tokens to deposit
/// @return amountSharesOut The amount of shares that would be minted
function previewDeposit(
address tokenIn,
uint256 amountTokenToDeposit
)
external
view
returns (uint256 amountSharesOut);
/// @notice Previews the amount of tokens received for a redemption
/// @param tokenOut The address of the token to receive
/// @param amountSharesToRedeem The amount of shares to redeem
/// @return amountTokenOut The amount of tokens that would be received
function previewRedeem(
address tokenOut,
uint256 amountSharesToRedeem
)
external
view
returns (uint256 amountTokenOut);
/// @notice Returns information about the asset
/// @return assetType The type of the asset
/// @return assetAddress The address of the asset
/// @return assetDecimals The decimals of the asset
function assetInfo()
external
view
returns (IStandardizedYield.AssetType assetType, address assetAddress, uint8 assetDecimals);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
//////////////////////////////////////////////////////////////
// STRUCTS //
//////////////////////////////////////////////////////////////
struct WrapperMetadata {
address formImplementation;
address underlyingVaultAddress;
address tokenIn;
address tokenOut;
address wrapper;
}
/// @title IERC5115To4626WrapperFactory
/// @dev Interface for 5115 to 4626 wrapper factory
/// @author ZeroPoint Labs
interface IERC5115To4626WrapperFactory {
//////////////////////////////////////////////////////////////
// EVENTS //
//////////////////////////////////////////////////////////////
/// @notice Emitted when a new wrapper is created
/// @param wrapper the address of the wrapper
/// @param wrapperKey the key of the wrapper
event WrapperCreated(address indexed wrapper, bytes32 wrapperKey);
/// @notice Emitted when a new wrapper is created with a superform
/// @param wrapper the address of the wrapper
/// @param wrapperKey the key of the wrapper
/// @param superformId the id of the superform
/// @param superform the address of the superform
event WrapperCreatedWithSuperform(
address indexed wrapper, bytes32 wrapperKey, uint256 superformId, address superform
);
/// @notice Emitted when a superform is created for an existing wrapper
/// @param wrapper the address of the wrapper
/// @param wrapperKey the key of the wrapper
/// @param superformId the id of the superform
/// @param superform the address of the superform
event CreatedSuperformForExistingWrapper(
address indexed wrapper, bytes32 wrapperKey, uint256 superformId, address superform
);
/// @notice Emitted when a wrapper is updated with a form implementation
/// @param wrapper the address of the wrapper
/// @param wrapperKey the key of the wrapper
/// @param formImplementation the address of the form implementation
event WrapperUpdatedWithImplementation(address indexed wrapper, bytes32 wrapperKey, address formImplementation);
//////////////////////////////////////////////////////////////
// ERRORS //
//////////////////////////////////////////////////////////////
/// @notice Reverts if a wrapper already exists for the given parameters
error WRAPPER_ALREADY_EXISTS();
/// @notice Reverts if the wrapper does not exist
error WRAPPER_DOES_NOT_EXIST();
/// @notice Revert if the wrapper already has a form implementation associated with it
error WRAPPER_ALREADY_HAS_FORM();
//////////////////////////////////////////////////////////////
// EXTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @notice Creates a new wrapper contract without creating a superform
/// @param underlyingVaultAddress_ the address of the underlying vault
/// @param tokenIn_ the address of the token to be deposited
/// @param tokenOut_ the address of the token to be withdrawn
function createWrapper(
address underlyingVaultAddress_,
address tokenIn_,
address tokenOut_
)
external
returns (address wrapper);
/// @notice Creates a new wrapper contract with a superform
/// @param formImplementationId_ the form implementation id
/// @param underlyingVaultAddress_ the address of the underlying vault
/// @param tokenIn_ the address of the token to be deposited
/// @param tokenOut_ the address of the token to be withdrawn
function createWrapperWithSuperform(
uint32 formImplementationId_,
address underlyingVaultAddress_,
address tokenIn_,
address tokenOut_
)
external
returns (address wrapper);
/// @notice Batch creates wrappers with superforms
/// @param formImplementationIds_ the form implementation ids
/// @param underlyingVaultAddresses the addresses of the underlying vaults
/// @param tokenIns the addresses of the tokens to be deposited
/// @param tokenOuts the addresses of the tokens to be withdrawn
function batchCreateWrappersWithSuperform(
uint32[] calldata formImplementationIds_,
address[] calldata underlyingVaultAddresses,
address[] calldata tokenIns,
address[] calldata tokenOuts
)
external
returns (address[] memory wrappers_);
/// @notice Creates a superform for an existing wrapper
/// @param wrapperKey the key of the wrapper
/// @param formImplementationId_ the form implementation id
function createSuperformForWrapper(
bytes32 wrapperKey,
uint32 formImplementationId_
)
external
returns (uint256 superformId, address superform);
/// @notice Batch updates the form implementation of multiple wrappers
/// @param wrapperKeys the keys of the wrappers to update
/// @param formImplementationIds the form implementation ids
function batchUpdateWrapperFormImplementation(
bytes32[] calldata wrapperKeys,
uint32[] calldata formImplementationIds
)
external;
}
// SPDX-License-Identifier: GPL-3.0-or-later
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
interface IStandardizedYield is IERC20Metadata {
/// @dev Emitted when any base tokens is deposited to mint shares
event Deposit(
address indexed caller,
address indexed receiver,
address indexed tokenIn,
uint256 amountDeposited,
uint256 amountSyOut
);
/// @dev Emitted when any shares are redeemed for base tokens
event Redeem(
address indexed caller,
address indexed receiver,
address indexed tokenOut,
uint256 amountSyToRedeem,
uint256 amountTokenOut
);
/// @dev check `assetInfo()` for more information
enum AssetType {
TOKEN,
LIQUIDITY
}
/// @dev Emitted when (`user`) claims their rewards
event ClaimRewards(address indexed user, address[] rewardTokens, uint256[] rewardAmounts);
/**
* @notice mints an amount of shares by depositing a base token.
* @param receiver shares recipient address
* @param tokenIn address of the base tokens to mint shares
* @param amountTokenToDeposit amount of base tokens to be transferred from (`msg.sender`)
* @param minSharesOut reverts if amount of shares minted is lower than this
* @return amountSharesOut amount of shares minted
* @dev Emits a {Deposit} event
*
* Requirements:
* - (`tokenIn`) must be a valid base token.
*/
function deposit(
address receiver,
address tokenIn,
uint256 amountTokenToDeposit,
uint256 minSharesOut
)
external
payable
returns (uint256 amountSharesOut);
/**
* @notice redeems an amount of base tokens by burning some shares
* @param receiver recipient address
* @param amountSharesToRedeem amount of shares to be burned
* @param tokenOut address of the base token to be redeemed
* @param minTokenOut reverts if amount of base token redeemed is lower than this
* @param burnFromInternalBalance if true, burns from balance of `address(this)`, otherwise burns from `msg.sender`
* @return amountTokenOut amount of base tokens redeemed
* @dev Emits a {Redeem} event
*
* Requirements:
* - (`tokenOut`) must be a valid base token.
*/
function redeem(
address receiver,
uint256 amountSharesToRedeem,
address tokenOut,
uint256 minTokenOut,
bool burnFromInternalBalance
)
external
returns (uint256 amountTokenOut);
/**
* @notice exchangeRate * syBalance / 1e18 must return the asset balance of the account
* @notice vice-versa, if a user uses some amount of tokens equivalent to X asset, the amount of sy
* he can mint must be X * exchangeRate / 1e18
* @dev SYUtils's assetToSy & syToAsset should be used instead of raw multiplication
* & division
*/
function exchangeRate() external view returns (uint256 res);
/**
* @notice claims reward for (`user`)
* @param user the user receiving their rewards
* @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`
* @dev
* Emits a `ClaimRewards` event
* See {getRewardTokens} for list of reward tokens
*/
function claimRewards(address user) external returns (uint256[] memory rewardAmounts);
/**
* @notice get the amount of unclaimed rewards for (`user`)
* @param user the user to check for
* @return rewardAmounts an array of reward amounts in the same order as `getRewardTokens`
*/
function accruedRewards(address user) external view returns (uint256[] memory rewardAmounts);
function rewardIndexesCurrent() external returns (uint256[] memory indexes);
function rewardIndexesStored() external view returns (uint256[] memory indexes);
/**
* @notice returns the list of reward token addresses
*/
function getRewardTokens() external view returns (address[] memory);
/**
* @notice returns the address of the underlying yield token
*/
function yieldToken() external view returns (address);
/**
* @notice returns all tokens that can mint this SY
*/
function getTokensIn() external view returns (address[] memory res);
/**
* @notice returns all tokens that can be redeemed by this SY
*/
function getTokensOut() external view returns (address[] memory res);
function isValidTokenIn(address token) external view returns (bool);
function isValidTokenOut(address token) external view returns (bool);
function previewDeposit(
address tokenIn,
uint256 amountTokenToDeposit
)
external
view
returns (uint256 amountSharesOut);
function previewRedeem(
address tokenOut,
uint256 amountSharesToRedeem
)
external
view
returns (uint256 amountTokenOut);
/**
* @notice This function contains information to interpret what the asset is
* @return assetType the type of the asset (0 for ERC20 tokens, 1 for AMM liquidity tokens,
* 2 for bridged yield bearing tokens like wstETH, rETH on Arbi whose the underlying asset doesn't exist on the
* chain)
* @return assetAddress the address of the asset
* @return assetDecimals the decimals of the asset
*/
function assetInfo() external view returns (AssetType assetType, address assetAddress, uint8 assetDecimals);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;
import { IAccessControl } from "openzeppelin-contracts/contracts/access/IAccessControl.sol";
/// @title ISuperRBAC
/// @dev Interface for SuperRBAC
/// @author Zeropoint Labs
interface ISuperRBAC is IAccessControl {
//////////////////////////////////////////////////////////////
// STRUCTS //
//////////////////////////////////////////////////////////////
struct InitialRoleSetup {
address admin;
address emergencyAdmin;
address paymentAdmin;
address csrProcessor;
address tlProcessor;
address brProcessor;
address csrUpdater;
address srcVaaRelayer;
address dstSwapper;
address csrRescuer;
address csrDisputer;
}
//////////////////////////////////////////////////////////////
// EVENTS //
//////////////////////////////////////////////////////////////
/// @dev is emitted when superRegistry is set
event SuperRegistrySet(address indexed superRegistry);
/// @dev is emitted when an admin is set for a role
event RoleAdminSet(bytes32 role, bytes32 adminRole);
//////////////////////////////////////////////////////////////
// EXTERNAL VIEW FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @dev returns the id of the protocol admin role
function PROTOCOL_ADMIN_ROLE() external view returns (bytes32);
/// @dev returns the id of the emergency admin role
function EMERGENCY_ADMIN_ROLE() external view returns (bytes32);
/// @dev returns the id of the payment admin role
function PAYMENT_ADMIN_ROLE() external view returns (bytes32);
/// @dev returns the id of the broadcaster role
function BROADCASTER_ROLE() external view returns (bytes32);
/// @dev returns the id of the core state registry processor role
function CORE_STATE_REGISTRY_PROCESSOR_ROLE() external view returns (bytes32);
/// @dev returns the id of the timelock state registry processor role
function TIMELOCK_STATE_REGISTRY_PROCESSOR_ROLE() external view returns (bytes32);
/// @dev returns the id of the broadcast state registry processor role
function BROADCAST_STATE_REGISTRY_PROCESSOR_ROLE() external view returns (bytes32);
/// @dev returns the id of the core state registry updater role
function CORE_STATE_REGISTRY_UPDATER_ROLE() external view returns (bytes32);
/// @dev returns the id of the dst swapper role
function DST_SWAPPER_ROLE() external view returns (bytes32);
/// @dev returns the id of the core state registry rescuer role
function CORE_STATE_REGISTRY_RESCUER_ROLE() external view returns (bytes32);
/// @dev returns the id of the core state registry rescue disputer role
function CORE_STATE_REGISTRY_DISPUTER_ROLE() external view returns (bytes32);
/// @dev returns the id of wormhole vaa relayer role
function WORMHOLE_VAA_RELAYER_ROLE() external view returns (bytes32);
/// @dev returns whether the given address has the protocol admin role
/// @param admin_ the address to check
function hasProtocolAdminRole(address admin_) external view returns (bool);
/// @dev returns whether the given address has the emergency admin role
/// @param admin_ the address to check
function hasEmergencyAdminRole(address admin_) external view returns (bool);
//////////////////////////////////////////////////////////////
// EXTERNAL WRITE FUNCTIONS //
//////////////////////////////////////////////////////////////
/// @dev updates the super registry address
function setSuperRegistry(address superRegistry_) external;
/// @dev configures a new role in superForm
/// @param role_ the role to set
/// @param adminRole_ the admin role to set as admin
function setRoleAdmin(bytes32 role_, bytes32 adminRole_) external;
/// @dev revokes the role_ from superRegistryAddressId_ on all chains
/// @param role_ the role to revoke
/// @param extraData_ amb config if broadcasting is required
/// @param superRegistryAddressId_ the super registry address id
function revokeRoleSuperBroadcast(
bytes32 role_,
bytes memory extraData_,
bytes32 superRegistryAddressId_
)
external
payable;
/// @dev allows sync of global roles from different chains using broadcast registry
/// @notice may not work for all roles
function stateSyncBroadcast(bytes memory data_) 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: 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;
}
}
{
"compilationTarget": {
"src/forms/wrappers/ERC5115To4626WrapperFactory.sol": "ERC5115To4626WrapperFactory"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@openzeppelin/contracts/=lib/ERC1155A/lib/openzeppelin-contracts/contracts/",
":ERC1155A/=lib/ERC1155A/src/",
":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/",
":solmate/=lib/ERC1155A/lib/solmate/src/",
":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/"
]
}
[{"inputs":[{"internalType":"address","name":"superRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ARRAY_LENGTH_MISMATCH","type":"error"},{"inputs":[],"name":"BLOCK_CHAIN_ID_OUT_OF_BOUNDS","type":"error"},{"inputs":[],"name":"FORM_DOES_NOT_EXIST","type":"error"},{"inputs":[],"name":"NOT_EMERGENCY_ADMIN","type":"error"},{"inputs":[],"name":"WRAPPER_ALREADY_EXISTS","type":"error"},{"inputs":[],"name":"WRAPPER_ALREADY_HAS_FORM","type":"error"},{"inputs":[],"name":"WRAPPER_DOES_NOT_EXIST","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wrapper","type":"address"},{"indexed":false,"internalType":"bytes32","name":"wrapperKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"superformId","type":"uint256"},{"indexed":false,"internalType":"address","name":"superform","type":"address"}],"name":"CreatedSuperformForExistingWrapper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wrapper","type":"address"},{"indexed":false,"internalType":"bytes32","name":"wrapperKey","type":"bytes32"}],"name":"WrapperCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wrapper","type":"address"},{"indexed":false,"internalType":"bytes32","name":"wrapperKey","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"superformId","type":"uint256"},{"indexed":false,"internalType":"address","name":"superform","type":"address"}],"name":"WrapperCreatedWithSuperform","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"wrapper","type":"address"},{"indexed":false,"internalType":"bytes32","name":"wrapperKey","type":"bytes32"},{"indexed":false,"internalType":"address","name":"formImplementation","type":"address"}],"name":"WrapperUpdatedWithImplementation","type":"event"},{"inputs":[],"name":"CHAIN_ID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"formImplementationIds_","type":"uint32[]"},{"internalType":"address[]","name":"underlyingVaultAddresses","type":"address[]"},{"internalType":"address[]","name":"tokenIns","type":"address[]"},{"internalType":"address[]","name":"tokenOuts","type":"address[]"}],"name":"batchCreateWrappersWithSuperform","outputs":[{"internalType":"address[]","name":"wrappers_","type":"address[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"wrapperKeys","type":"bytes32[]"},{"internalType":"uint32[]","name":"formImplementationIds","type":"uint32[]"}],"name":"batchUpdateWrapperFormImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"wrapperKey","type":"bytes32"},{"internalType":"uint32","name":"formImplementationId_","type":"uint32"}],"name":"createSuperformForWrapper","outputs":[{"internalType":"uint256","name":"superformId","type":"uint256"},{"internalType":"address","name":"superform","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"underlyingVaultAddress_","type":"address"},{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"}],"name":"createWrapper","outputs":[{"internalType":"address","name":"wrapper","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"formImplementationId_","type":"uint32"},{"internalType":"address","name":"underlyingVaultAddress_","type":"address"},{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"}],"name":"createWrapperWithSuperform","outputs":[{"internalType":"address","name":"wrapper","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superRegistry","outputs":[{"internalType":"contract ISuperRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"wrapperKey","type":"bytes32"}],"name":"wrappers","outputs":[{"internalType":"address","name":"formImplementation","type":"address"},{"internalType":"address","name":"underlyingVaultAddress","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"address","name":"wrapper","type":"address"}],"stateMutability":"view","type":"function"}]