Overview
POL Balance
0 POL
POL Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 11 from a total of 11 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Multicall | 65125073 | 18 days ago | IN | 0 POL | 0.00707115 | ||||
Multicall | 65033894 | 20 days ago | IN | 0 POL | 0.02205947 | ||||
Multicall | 64832522 | 25 days ago | IN | 0 POL | 0.00608335 | ||||
Multicall | 64761971 | 27 days ago | IN | 0 POL | 0.01858262 | ||||
Multicall | 64728349 | 28 days ago | IN | 0 POL | 0.00789918 | ||||
Multicall | 64598261 | 31 days ago | IN | 0 POL | 0.01974438 | ||||
Multicall | 64567682 | 32 days ago | IN | 0 POL | 0.00644343 | ||||
Multicall | 64563987 | 32 days ago | IN | 0 POL | 0.01234625 | ||||
Multicall | 64478594 | 34 days ago | IN | 0 POL | 0.01590325 | ||||
Multicall | 64243279 | 40 days ago | IN | 0 POL | 0.00416256 | ||||
Multicall | 64241551 | 40 days ago | IN | 0 POL | 0.02138777 |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
DelayedWithdrawalManager
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 10000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >=0.8.22; import { INFTPermissions } from "@balmy/nft-permissions/interfaces/INFTPermissions.sol"; import { IDelayedWithdrawalManager, IEarnVault } from "../interfaces/IDelayedWithdrawalManager.sol"; import { IDelayedWithdrawalAdapter } from "../interfaces/IDelayedWithdrawalAdapter.sol"; import { StrategyId, StrategyIdConstants } from "@balmy/earn-core/types/StrategyId.sol"; import { IEarnBalmyStrategy, IEarnStrategy } from "../interfaces/IEarnBalmyStrategy.sol"; // solhint-disable-next-line no-unused-import import { RegisteredAdapter, RegisteredAdaptersLibrary, PositionIdTokenKey } from "./types/RegisteredAdapters.sol"; import { PayableMulticall } from "src/base/PayableMulticall.sol"; contract DelayedWithdrawalManager is IDelayedWithdrawalManager, PayableMulticall { using RegisteredAdaptersLibrary for mapping(uint256 => mapping(address => mapping(uint256 => RegisteredAdapter))); using RegisteredAdaptersLibrary for mapping(uint256 => RegisteredAdapter); // slither-disable-start naming-convention mapping(uint256 position => mapping(address token => mapping(uint256 index => RegisteredAdapter registeredAdapter))) internal _registeredAdapters; /// @inheritdoc IDelayedWithdrawalManager // solhint-disable-next-line var-name-mixedcase IEarnVault public immutable VAULT; // solhint-disable-next-line var-name-mixedcase INFTPermissions.Permission private immutable WITHDRAW_PERMISSION; // slither-disable-end naming-convention constructor(IEarnVault vault) { VAULT = vault; WITHDRAW_PERMISSION = vault.WITHDRAW_PERMISSION(); } /// @inheritdoc IDelayedWithdrawalManager function estimatedPendingFunds(uint256 positionId, address token) public view returns (uint256 pendingFunds) { mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters = _registeredAdapters.get(positionId, token); uint256 i = 0; bool shouldContinue = true; while (shouldContinue) { RegisteredAdapter memory adapter = registeredAdapters[i]; if (address(adapter.adapter) != address(0)) { // slither-disable-next-line calls-loop pendingFunds += adapter.adapter.estimatedPendingFunds(positionId, token); unchecked { ++i; } } shouldContinue = adapter.isNextFilled; } } /// @inheritdoc IDelayedWithdrawalManager function withdrawableFunds(uint256 positionId, address token) public view returns (uint256 funds) { mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters = _registeredAdapters.get(positionId, token); uint256 i = 0; bool shouldContinue = true; while (shouldContinue) { RegisteredAdapter memory adapter = registeredAdapters[i]; if (address(adapter.adapter) != address(0)) { // slither-disable-next-line calls-loop funds += adapter.adapter.withdrawableFunds(positionId, token); unchecked { ++i; } } shouldContinue = adapter.isNextFilled; } } /// @inheritdoc IDelayedWithdrawalManager function allPositionFunds(uint256 positionId) external view returns (address[] memory tokens, uint256[] memory estimatedPending, uint256[] memory withdrawable) { // slither-disable-next-line unused-return (tokens,,,) = VAULT.position(positionId); uint256 tokensQuantity = tokens.length; estimatedPending = new uint256[](tokensQuantity); withdrawable = new uint256[](tokensQuantity); // slither-disable-start calls-loop for (uint256 i; i < tokensQuantity; ++i) { address token = tokens[i]; mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters = _registeredAdapters.get(positionId, token); uint256 j = 0; bool shouldContinue = true; while (shouldContinue) { RegisteredAdapter memory adapter = registeredAdapters[j]; if (address(adapter.adapter) != address(0)) { withdrawable[i] += adapter.adapter.withdrawableFunds(positionId, token); estimatedPending[i] += adapter.adapter.estimatedPendingFunds(positionId, token); unchecked { ++j; } } shouldContinue = adapter.isNextFilled; } // slither-disable-end calls-loop } } /// @inheritdoc IDelayedWithdrawalManager function registerDelayedWithdraw(uint256 positionId, address token) external { _revertIfNotCurrentStrategyAdapter(positionId, token); mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters = _registeredAdapters.get(positionId, token); (bool isRepeated, uint256 length) = registeredAdapters.isRepeated(IDelayedWithdrawalAdapter(msg.sender)); if (isRepeated) { revert AdapterDuplicated(); } registeredAdapters.set(length, IDelayedWithdrawalAdapter(msg.sender)); // slither-disable-next-line reentrancy-events emit DelayedWithdrawalRegistered(positionId, token, msg.sender); } /// @inheritdoc IDelayedWithdrawalManager function withdraw( uint256 positionId, address token, address recipient ) external returns (uint256 withdrawn, uint256 stillPending) { if (!VAULT.hasPermission(positionId, msg.sender, WITHDRAW_PERMISSION)) revert UnauthorizedWithdrawal(); mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters = _registeredAdapters.get(positionId, token); uint256 j = 0; uint256 i = 0; bool shouldContinue = true; while (shouldContinue) { RegisteredAdapter memory adapter = registeredAdapters[i]; if (address(adapter.adapter) != address(0)) { // slither-disable-next-line calls-loop (uint256 _withdrawn, uint256 _stillPending) = adapter.adapter.withdraw(positionId, token, recipient); withdrawn += _withdrawn; stillPending += _stillPending; if (_stillPending != 0) { if (i != j) { registeredAdapters.set(j, adapter.adapter); } unchecked { ++j; } } unchecked { ++i; } } shouldContinue = adapter.isNextFilled; } registeredAdapters.pop({ start: j, end: i }); // slither-disable-next-line reentrancy-events emit WithdrawnFunds(positionId, token, recipient, withdrawn); } function _revertIfNotCurrentStrategyAdapter(uint256 positionId, address token) internal view { (StrategyId strategyId, IEarnStrategy strategy) = VAULT.positionsStrategy(positionId); if (strategyId == StrategyIdConstants.NO_STRATEGY) revert AdapterMismatch(); if (!strategy.supportsInterface(type(IEarnBalmyStrategy).interfaceId)) revert AdapterMismatch(); IDelayedWithdrawalAdapter adapter = IEarnBalmyStrategy(address(strategy)).delayedWithdrawalAdapter(token); if (address(adapter) != msg.sender) revert AdapterMismatch(); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; interface INFTPermissions is IERC721 { type Permission is uint8; /// @notice A collection of permissions sets for a specific position struct PositionPermissions { // The id of the position uint256 positionId; // The permissions to assign to the position PermissionSet[] permissionSets; } /// @notice A set of permissions for a specific operator struct PermissionSet { // The address of the operator address operator; // The permissions given to the operator Permission[] permissions; } /** * @notice Emitted when permissions for a position are modified * @param positionId The id of the position * @param permissions The set of permissions that were updated */ event ModifiedPermissions(uint256 positionId, PermissionSet[] permissions); /// @notice Thrown when a user tries to modify permissions for a position they do not own error NotOwner(); /// @notice Thrown when a user tries to execute a permit with an expired deadline error ExpiredDeadline(); /// @notice Thrown when a user tries to execute a permit with an invalid signature error InvalidSignature(); /// @notice Thrown when a user tries perform an operation without permission error AccountWithoutPermission(uint256 positionId, address account, Permission permission); /** * @notice The domain separator used in the permit signature * @return The domain seperator used in encoding of permit signature */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); /** * @notice Returns the next nonce to use for a given user * @param account The address of the user * @return The next nonce to use */ function nextNonce(address account) external view returns (uint256); /** * @notice Returns the block number where the ownership of the position last changed * @param positionId The position to check * @return The block number */ function lastOwnershipChange(uint256 positionId) external view returns (uint256); /** * @notice Returns how many NFTs are currently tracked by this contract * @return How many of valid NFTs are tracked by this contract, where each one of * them has an assigned and queryable owner not equal to the zero address */ function totalSupply() external view returns (uint256); /** * @notice Returns whether the given account has the permission for the given position * @param positionId The id of the position to check * @param account The address of the user to check * @param permission The permission to check * @return Whether the user has the permission or not */ function hasPermission(uint256 positionId, address account, Permission permission) external view returns (bool); /** * @notice Sets new permissions for the given positions * @dev Will revert if called by someone who is not the owner of all positions * @param positionPermissions A list of position permissions to set */ function modifyPermissions(PositionPermissions[] calldata positionPermissions) external; /** * @notice Sets permissions via signature * @param permissions The permissions to set for the different positions * @param deadline The deadline timestamp by which the call must be mined for the approve to work * @param signature The signature */ function permissionPermit(PositionPermissions[] calldata permissions, uint256 deadline, bytes calldata signature) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { IEarnVault } from "@balmy/earn-core/interfaces/IEarnVault.sol"; /** * @title Delayed Withdrawal Manager Interface * @notice This contract will reference all delayed withdraws for all positions. When a delayed withdrawal is started, * the Earn strategy will delegate the withdrawal to a delayed withdraw adapter. That adapter is the one that * will start the withdraw, and then register itself to the manager. By doing so, we will be able to track all * pending withdrawals for a specific position in one place (here). */ interface IDelayedWithdrawalManager { /** * @notice Thrown when trying to register a delayed withdraw from an address that doesn't correspond with the token * adapter */ error AdapterMismatch(); /// @notice Thrown when trying to register a delayed withdraw for the same token and position twice error AdapterDuplicated(); /// @notice Thrown when trying to withdraw funds for a position without withdrawal permission error UnauthorizedWithdrawal(); /** * @notice Emitted when funds have been withdrawn * @param positionId The position to withdraw * @param token The token to withdraw * @param recipient The withdraw recipient * @param withdrawn How much was withdrawn */ event WithdrawnFunds(uint256 positionId, address token, address recipient, uint256 withdrawn); /** * @notice Emitted when a delayed withdrawal is registered * @param positionId The position to associate the withdrawal to * @param token The token that is being withdrawn * @param adapter The delayed withdrawal adapter responsible for processing the withdrawal */ event DelayedWithdrawalRegistered(uint256 positionId, address token, address adapter); /** * @notice Returns the address to Earn's vault * @return Earn's vault address */ // slither-disable-next-line naming-convention function VAULT() external view returns (IEarnVault); /** * @notice Returns the estimated amount of funds that are pending for withdrawal. Note that this amount is estimated * because the underlying farm might not be able to guarantee an exit amount when it is first started * @param positionId The position that executed the withdrawal * @param token The token that is being withdrawn * @return The estimated amount of funds that are pending for withdrawal */ function estimatedPendingFunds(uint256 positionId, address token) external view returns (uint256); /** * @notice Returns the amount of funds that are available for withdrawal * @param positionId The position that executed the withdrawal * @param token The token that is being withdrawn * @return The amount of funds that are available for withdrawal */ function withdrawableFunds(uint256 positionId, address token) external view returns (uint256); /** * @notice Returns the total amounts of funds that are pending or withdrawable, for a given position * @param positionId The position to check * @return tokens The position's tokens * @return estimatedPending The estimated amount of funds that are pending for withdrawal * @return withdrawable The amount of funds that are available for withdrawal */ function allPositionFunds(uint256 positionId) external view returns (address[] memory tokens, uint256[] memory estimatedPending, uint256[] memory withdrawable); /** * @notice Registers a delayed withdrawal for the given position and token * @dev Must be called by a delayed withdrawal adapter that is referenced by the position's strategy * @param positionId The position to associate the withdrawal to * @param token The token that is being withdrawn */ function registerDelayedWithdraw(uint256 positionId, address token) external; /** * @notice Completes a delayed withdrawal for a given position and token * @dev The caller must have withdraw permissions over the position * If there are no withdrawable funds associated to the position, will just return 0 * @param positionId The position that executed the withdrawal * @param token The token that is being withdrawn * @param recipient The account that will receive the funds * @return withdrawn How much was withdrawn * @return stillPending How much is still pending */ function withdraw( uint256 positionId, address token, address recipient ) external returns (uint256 withdrawn, uint256 stillPending); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; import { IEarnVault } from "@balmy/earn-core/interfaces/IEarnVault.sol"; import { IDelayedWithdrawalManager } from "./IDelayedWithdrawalManager.sol"; /** * @title Delayed Withdrawal Adapter Interface * @notice This contract will interact with one or more farms and handle the process of withdrawing funds that have a * lock up period. When a withdrawal is initiated, adapters will register themselves to the manager, to * help with discoverability. Only the manager can process a finished withdrawal */ interface IDelayedWithdrawalAdapter is IERC165 { /** * @notice Thrown when the sender is not the delayed withdrawal manager */ error UnauthorizedDelayedWithdrawalManager(); /** * @notice Thrown when the sender is not the position's strategy */ error UnauthorizedPositionStrategy(); /** * @notice Returns the address to Earn's vault * @return Earn's vault address */ function vault() external view returns (IEarnVault); /** * @notice Returns the address to Earn's delayed withdrawal manager * @return Earn's delayed withdrawal manager's address */ function manager() external view returns (IDelayedWithdrawalManager); /** * @notice Returns the estimated amount of funds that are pending for withdrawal. Note that this amount is estimated * because the underlying farm might not be able to guarantee an exit amount when the withdraw is started * @param positionId The position that executed the withdrawal * @param token The token that is being withdrawn * @return The estimated amount of funds that are pending for withdrawal */ function estimatedPendingFunds(uint256 positionId, address token) external view returns (uint256); /** * @notice Returns the amount of funds that are available for withdrawal * @param positionId The position that executed the withdrawal * @param token The token that is being withdrawn * @return The amount of funds that are available for withdrawal */ function withdrawableFunds(uint256 positionId, address token) external view returns (uint256); /** * @notice Starts a delayed withdrawal, and associates it to the position * @dev Can only be called by the position's strategy. * @param positionId The position to associate to the withdrawal * @param token The token that is being withdrawn * @param amount The amount of input for the withdrawal to use. Each adapter might provide different meaning to this * value */ function initiateDelayedWithdrawal(uint256 positionId, address token, uint256 amount) external; /** * @notice Completes a delayed withdrawal for a given position and token * @dev Can only be called by the delayed withdrawal manager * If there are no withdrawable funds associated to the given parameters, will just return 0 * @param positionId The position that executed the withdrawal * @param token The token that is being withdrawn * @param recipient The account that will receive the funds * @return withdrawn How much was withdrawn * @return stillPending How much is still pending */ function withdraw( uint256 positionId, address token, address recipient ) external returns (uint256 withdrawn, uint256 stillPending); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; type StrategyId is uint96; using { increment, equals as ==, notEquals as != } for StrategyId global; function increment(StrategyId id) pure returns (StrategyId) { return StrategyId.wrap(StrategyId.unwrap(id) + 1); } // slither-disable-next-line dead-code function equals(StrategyId id1, StrategyId id2) pure returns (bool) { return StrategyId.unwrap(id1) == StrategyId.unwrap(id2); } function notEquals(StrategyId id1, StrategyId id2) pure returns (bool) { return StrategyId.unwrap(id1) != StrategyId.unwrap(id2); } library StrategyIdConstants { StrategyId internal constant NO_STRATEGY = StrategyId.wrap(0); StrategyId internal constant INITIAL_STRATEGY_ID = StrategyId.wrap(1); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { IEarnStrategy } from "@balmy/earn-core/interfaces/IEarnStrategy.sol"; import { IDelayedWithdrawalAdapter } from "./IDelayedWithdrawalAdapter.sol"; /// @notice Interface for Earn strategies that support delayed withdrawals interface IEarnBalmyStrategy is IEarnStrategy { /** * @notice Returns the "delayed withdrawal" adapter that will be used for the given token * @param token The token to use the adapter for * @return The address of the "delayed withdrawal" adapter, or the zero address if none is configured */ function delayedWithdrawalAdapter(address token) external view returns (IDelayedWithdrawalAdapter); /** * @notice Returns a yield coefficient that, when calculated over time, describes how much yield was * generated by the strategy * @return coefficient The yield coefficient * @return multiplier The multiplier used for the coefficient */ function assetYieldCoefficient() external view returns (uint256 coefficient, uint256 multiplier); /** * @notice Returns the rewards emitted per second for each reward token. This value represents how many * reward tokens are emitted per deposited asset * @return emissions The rewards emitted per second for each reward token * @return multipliers The multiplier used for each emission value */ function rewardEmissionsPerSecondPerAsset() external view returns (uint256[] memory emissions, uint256[] memory multipliers); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.22; import { IDelayedWithdrawalAdapter } from "src/interfaces/IDelayedWithdrawalAdapter.sol"; struct RegisteredAdapter { IDelayedWithdrawalAdapter adapter; bool isNextFilled; } /// @notice A key composed of a position id and a token address type PositionIdTokenKey is bytes32; library RegisteredAdaptersLibrary { /// @notice Get all adapters for a position and token function get( mapping(uint256 => mapping(address => mapping(uint256 index => RegisteredAdapter registeredAdapter))) storage registeredAdapters, uint256 positionId, address token ) internal view returns (mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapter) { return registeredAdapters[positionId][token]; } /// @notice Checks if an adapter is repeated in the list of registered adapters for a position and token function isRepeated( mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters, IDelayedWithdrawalAdapter adapter ) internal view returns (bool, uint256) { uint256 length = 0; bool shouldContinue = true; while (shouldContinue) { RegisteredAdapter memory adapterToCompare = registeredAdapters[length]; if (adapterToCompare.adapter == adapter) { // Since we won't be using the length, we can return any value return (true, 0); } if (address(adapterToCompare.adapter) != address(0)) { unchecked { ++length; } } shouldContinue = adapterToCompare.isNextFilled; } return (false, length); } function set( mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters, uint256 index, IDelayedWithdrawalAdapter adapter ) internal { if (index != 0) registeredAdapters[index - 1].isNextFilled = true; registeredAdapters[index] = RegisteredAdapter({ adapter: adapter, isNextFilled: false }); } function pop( mapping(uint256 index => RegisteredAdapter registeredAdapter) storage registeredAdapters, uint256 start, uint256 end ) internal { for (uint256 i = start; i < end; ++i) { delete registeredAdapters[i]; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.22; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; /** * @dev Adding this contract will enable batching calls. This is basically the same as Open Zeppelin's * Multicall contract, but we have made it payable. It supports both payable and non payable * functions. However, if `msg.value` is not zero, then non payable functions cannot be called. * Any contract that uses this Multicall version should be very careful when using msg.value. * For more context, read: https://github.com/Uniswap/v3-periphery/issues/52 */ abstract contract PayableMulticall { /** * @notice Receives and executes a batch of function calls on this contract. * @param data A list of different function calls to execute * @return results The result of executing each of those calls */ function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; ++i) { results[i] = Address.functionDelegateCall(address(this), data[i]); } return results; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC-721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { INFTPermissions } from "@balmy/nft-permissions/interfaces/INFTPermissions.sol"; import { IEarnStrategyRegistry } from "../interfaces/IEarnStrategyRegistry.sol"; import { IEarnStrategy } from "./IEarnStrategy.sol"; import { IEarnNFTDescriptor } from "./IEarnNFTDescriptor.sol"; import { StrategyId } from "../types/StrategyId.sol"; import { SpecialWithdrawalCode } from "../types/SpecialWithdrawals.sol"; /** * @title Earn Vault Interface * @notice Earn's vault is the place where users deposit and withdraw their funds and rewards. Earn has a singleton * vault contract, which will be the one that keeps track of who owns what. It is also the one that implements * access control and makes sure that users can only access their own funds. */ interface IEarnVault is INFTPermissions { /// @notice Thrown when a user tries to make an empty deposit error ZeroAmountDeposit(); /// @notice Thrown when a deposit earns the caller zero shares error ZeroSharesDeposit(); /// @notice Thrown when the withdraw input is invalid error InvalidWithdrawInput(); /// @notice Thrown when trying to withdraw amount exceeds balance error InsufficientFunds(); /// @notice Emitted when a new position is created event PositionCreated( uint256 indexed positionId, address indexed owner, StrategyId strategyId, address depositedToken, uint256 depositedAmount, uint256 assetsDeposited, INFTPermissions.PermissionSet[] permissions, bytes misc ); /// @notice Emitted when a new position is increased event PositionIncreased( uint256 indexed positionId, address depositedToken, uint256 depositedAmount, uint256 assetsDeposited ); /// @notice Emitted when a new position is withdrawn event PositionWithdrawn(uint256 indexed positionId, address[] tokens, uint256[] withdrawn, address recipient); /// @notice Emitted when a new position is withdrawn specially event PositionWithdrawnSpecially( uint256 indexed positionId, address[] tokens, uint256[] balanceChanges, address[] actualWithdrawnTokens, uint256[] actualWithdrawnAmounts, bytes result, address recipient ); /** * @notice Returns the role in charge of pausing/unpausing deposits * @return The role in charge of pausing/unpausing deposits */ // slither-disable-next-line naming-convention function PAUSE_ROLE() external pure returns (bytes32); /** * @notice Returns the id of the "increase" permission * @return The id of the "increase" permission */ // slither-disable-next-line naming-convention function INCREASE_PERMISSION() external pure returns (Permission); /** * @notice Returns the id of the "withdraw" permission * @return The id of the "withdraw" permission */ // slither-disable-next-line naming-convention function WITHDRAW_PERMISSION() external pure returns (Permission); /** * @notice Returns the address of the strategy registry * @return The address of the strategy registry */ // slither-disable-next-line naming-convention function STRATEGY_REGISTRY() external view returns (IEarnStrategyRegistry); /** * @notice Returns the NFT descriptor contract * @return The contract for the NFT descriptor */ // slither-disable-next-line naming-convention function NFT_DESCRIPTOR() external view returns (IEarnNFTDescriptor); /** * @notice Returns the strategy chosen by the given position * @param positionId The position to check * @return strategyId The strategy chosen by the given position. Will return 0 if the position doesn't exist * @return strategy The strategy's address. Will return the zero address if the position doesn't exist */ function positionsStrategy(uint256 positionId) external view returns (StrategyId strategyId, IEarnStrategy strategy); /** * @notice Returns a summary of the position's balances * @param positionId The position to check the balances for * @return tokens All of the position's tokens * @return balances Total balance of each token * @return strategyId The position's strategy id * @return strategy The position's strategy address */ function position(uint256 positionId) external view returns (address[] memory tokens, uint256[] memory balances, StrategyId strategyId, IEarnStrategy strategy); /** * @notice Returns if deposits and paused * @return Whether deposits are paused or not */ function paused() external view returns (bool); /** * @notice Creates a new position with the given strategy owner and permissions * @param strategyId The strategy to use for this position * @param depositToken The token to use for the initial deposit * @param depositAmount The amount to deposit. If it's max(uint256), then all balance will be taken from the caller * Using max(uint256) and the native token will end up in revert * @param owner The owner to set for the position * @param permissions The permissions to set for the position * @param strategyValidationData Data used by the strategy to determine if the position can be created * @param misc Miscellaneous bytes to emit, can work for referrals and more * @return positionId The id of the created position * @return assetsDeposited How much was actually deposited in terms of the asset */ function createPosition( StrategyId strategyId, address depositToken, uint256 depositAmount, address owner, INFTPermissions.PermissionSet[] calldata permissions, bytes calldata strategyValidationData, bytes calldata misc ) external payable returns (uint256 positionId, uint256 assetsDeposited); /** * @notice Deposits more funds into an existing position * @dev The caller must have permissions to increase the position * @param positionId The position to add funds to * @param depositToken The token to use for the initial deposit * @param depositAmount The amount to deposit. If it's max(uint256), then all balance will be taken from the caller * Using max(uint256) and the native token will end up in revert * @return assetsDeposited How much was actually deposited in terms of the asset */ function increasePosition( uint256 positionId, address depositToken, uint256 depositAmount ) external payable returns (uint256 assetsDeposited); /** * @notice Withdraws funds from an existing position * @dev The caller must have permissions to withdraw from the position * @param positionId The position to withdraw funds from * @param tokensToWithdraw All position's tokens, in the same order as returned on `position` * @param intendedWithdraw The amounts to withdraw from the position. You can set to max(uint256) to withdraw all * that's available. Note that if a token doesn't support and immediate withdrawal, then * a delayed withdrawal will be started * @param recipient The account that will receive the withdrawn funds * @return withdrawn How much was actually withdrawn from each token * @return withdrawalTypes The type of withdrawal for each token */ function withdraw( uint256 positionId, address[] calldata tokensToWithdraw, uint256[] calldata intendedWithdraw, address recipient ) external payable returns (uint256[] memory withdrawn, IEarnStrategy.WithdrawalType[] memory withdrawalTypes); /** * @notice Performs a special withdrawal against the strategy. This is meant to be used be used in special cases, like * withdrawing the farm token directly, instead of the asset. The withdraw data and result can be different * for each strategy * @dev The caller must have permissions to withdraw from the position * @param positionId The position to withdraw funds from * @param withdrawalCode The code that identifies the special withdrawal * @param toWithdraw Amounts to withdraw, based on the withdrawal code. Does not need to have the same * length or order as `tokens` * @param withdrawalData The data that defines the withdrawal * @param recipient The account that will receive the withdrawn funds * @return tokens All of the position's tokens * @return balanceChanges Changes in the position's balances, in the same order as `tokens` * @return actualWithdrawnTokens The tokens that were actually withdrawn * @return actualWithdrawnAmounts How much was withdrawn from each token * @return result The result of the withdrawal. Can be different for each strategy */ function specialWithdraw( uint256 positionId, SpecialWithdrawalCode withdrawalCode, uint256[] calldata toWithdraw, bytes calldata withdrawalData, address recipient ) external payable returns ( address[] memory tokens, uint256[] memory balanceChanges, address[] memory actualWithdrawnTokens, uint256[] memory actualWithdrawnAmounts, bytes memory result ); /** * @notice Pauses position creations and increases * @dev Can only be called by someone with the `PAUSE_ROLE` role */ function pause() external payable; /** * @notice Unpauses position creations and increases * @dev Can only be called by someone with the `PAUSE_ROLE` role */ function unpause() external payable; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { IERC165 } from "@openzeppelin/contracts/interfaces/IERC165.sol"; import { IEarnStrategyRegistry } from "./IEarnStrategyRegistry.sol"; import { IEarnVault } from "./IEarnVault.sol"; import { StrategyId } from "../types/StrategyId.sol"; import { SpecialWithdrawalCode } from "../types/SpecialWithdrawals.sol"; /** * @title Earn Strategy Interface * @notice In Earn, a strategy will take an asset (could be ERC20 or native) and generate yield with it. The generated * yield could be in the same asset, or in other tokens. One strategy could generate yield on multiple tokens * at the same time * @dev For the proper functioning of the platform, there are some restrictions that strategy devs must consider: * - The asset cannot change over time, it must always be the same * - The strategy must report the asset as the first token * - Tokens can never be removed from the list. New ones can be added, but they cannot be removed later * - Functions like `withdrawalTypes` and `balances` must return the same amount of values as `tokens`, and * in the same order too * - Tokens with very high supplies or a high amount of decimals might not fit correctly into the Vault's * accounting system. For more information about this, please refer to the [README](../vault/README.md). * Take into account some strategies might not support an immediate withdraw of all tokens, since they * might implement a lock up period. If that's the case, then executing a withdraw will start what we call a * "delayed withdrawal". This is a process where the funds are sent to a "delayed withdrawal" adapter, * which is in charge of handling this process. Users will be able to monitor their funds through the * "delayed withdrawal" manager, who aggregates all available adapters. Finally, once the withdrawal can be * executed, only those with withdraw permissions over the position will be able to retrieve the funds */ interface IEarnStrategy is IERC165 { /// @notice The type of withdrawal supported for a specific token enum WithdrawalType { IMMEDIATE, DELAYED } /// @notice The type of fee charged for a specific token enum FeeType { PERFORMANCE, DEPOSIT, WITHDRAW, RESCUE, OTHER } /** * @notice Returns the address to Earn's vault * @return Earn's vault address */ function vault() external view returns (IEarnVault); /** * @notice Returns the address to Earn's strategy registry * @return Earn's strategy registry address */ function registry() external view returns (IEarnStrategyRegistry); /** * @notice Returns the asset this strategy will use to generate yield * @return The asset this strategy will use to generate yield */ function asset() external view returns (address); /** * @notice Returns the strategy's description * @return The strategy's description */ function description() external view returns (string memory); /** * @notice Returns all tokens under the strategy's control * @dev The asset must be the first token returned * @return tokens All tokens under the strategy's control */ function allTokens() external view returns (address[] memory tokens); /** * @notice Returns the types of withdrawals supported for each token * @dev In the same order returned as `tokens` * @return The types of withdrawals for each token */ function supportedWithdrawals() external view returns (WithdrawalType[] memory); /** * @notice Returns whether a specific token can be used to deposit funds into the strategy * @param depositToken The token to check * @return Whether the given token can be used to deposit funds into the strategy */ function isDepositTokenSupported(address depositToken) external view returns (bool); /** * @notice Returns all tokens that can be used to deposit funds into the strategy * @return All tokens that can be used to deposit funds into the strategy */ function supportedDepositTokens() external view returns (address[] memory); /** * @notice Returns how much can be deposited from the given token * @dev Will return 0 if the token is not supported * @return How much can be deposited from the given token */ function maxDeposit(address depositToken) external view returns (uint256); /** * @notice Returns how many tokens are currently under the strategy's control */ function totalBalances() external view returns (address[] memory tokens, uint256[] memory balances); /** * @notice Returns whether a specific withdrawal method can be used * @param withdrawalCode The withdrawal method to check * @return Whether the given withdrawal method can be used to withdraw funds */ function isSpecialWithdrawalSupported(SpecialWithdrawalCode withdrawalCode) external view returns (bool); /** * @notice Returns all withdrawal methods can be used to withdraw funds * @return All withdrawal methods can be used to withdraw funds */ function supportedSpecialWithdrawals() external view returns (SpecialWithdrawalCode[] memory); /** * @notice Returns how much can be withdrawn at this moment * @return tokens All tokens under the strategy's control * @return withdrawable How much can be withdrawn for each one */ function maxWithdraw() external view returns (address[] memory tokens, uint256[] memory withdrawable); /** * @notice Returns how much is charged in terms of fees, for each token * @return types The type of fee charged for each token * @return bps How much fee is being charged, in basis points */ function fees() external view returns (FeeType[] memory types, uint16[] memory bps); /** * @notice Notifies the strategy that funds have been deposited into it * @dev Will revert if the given token is not supported * @param depositToken The token that was deposited * @param depositAmount The amount that was deposited * @return assetsDeposited How much was deposited, measured in asset */ function deposited(address depositToken, uint256 depositAmount) external payable returns (uint256 assetsDeposited); /** * @notice Executes a withdraw, for the given tokens and amounts. If a token only supports delayed withdrawals, * then one will be started and associated to the given position * @dev Can only be called by the vault * @param positionId The position that initiated the withdrawal * @param tokens All tokens supported by the strategy, in the same order as in `tokens` * @param toWithdraw How much to withdraw from each * @param recipient The account that will receive the tokens * @return The types of withdrawals for each token */ function withdraw( uint256 positionId, address[] memory tokens, uint256[] memory toWithdraw, address recipient ) external returns (WithdrawalType[] memory); /** * @notice Executes a special withdraw * @dev Can only be called by the vault * @param positionId The position that initiated the withdrawal * @param withdrawalCode The code that identifies the type of withdrawal * @param toWithdraw Amounts to withdraw, based on the withdrawal code. Does not need to have the same * length or order as `tokens` * @param withdrawalData Data necessary to execute the withdrawal * @param recipient The account that will receive the tokens * @return balanceChanges Changes in the position's balances * @return actualWithdrawnTokens The tokens that were actually withdrawn * @return actualWithdrawnAmounts How much was withdrawn from each token * @return result Some custom data related to the withdrawal */ function specialWithdraw( uint256 positionId, SpecialWithdrawalCode withdrawalCode, uint256[] calldata toWithdraw, bytes calldata withdrawalData, address recipient ) external returns ( uint256[] memory balanceChanges, address[] memory actualWithdrawnTokens, uint256[] memory actualWithdrawnAmounts, bytes memory result ); /** * @notice Migrates all tokens and data to a new strategy * @dev Can only be called by the strategy registry * @param newStrategy The strategy to migrate to * @param migrationData Data to be used as part of the migration * @return Data related to the result of the migration. Will be sent to the new strategy */ function migrateToNewStrategy( IEarnStrategy newStrategy, bytes calldata migrationData ) external returns (bytes memory); /** * @notice Performs any necessary preparations to be used by the vault * @dev Can only be called by the strategy registry * @param strategyId The id that this strategy was registered to * @param oldStrategy The previous strategy registered to the id. Will be the zero address if this is the first * strategy registered to the id * @param migrationResultData Data sent by the previous strategy registered to the id. Will be empty if this is the * first strategy registered to the id */ function strategyRegistered( StrategyId strategyId, IEarnStrategy oldStrategy, bytes calldata migrationResultData ) external; /** * @notice Validates if the position can be created for this strategy, and fails it it can't * @param sender The address to be checked * @param creationData The hash to check with the sender */ function validatePositionCreation(address sender, bytes calldata creationData) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @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 Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @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 * {Errors.FailedCall} 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 Errors.InsufficientBalance(address(this).balance, value); } (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 {Errors.FailedCall}) 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 {Errors.FailedCall} 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 {Errors.FailedCall}. */ 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 assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC-165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[ERC]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { IEarnStrategy } from "./IEarnStrategy.sol"; import { StrategyId } from "../types/StrategyId.sol"; /** * @title Earn Strategy Registry Interface * @notice This contract will act as a registry, so that Earn strategies can be updated. It will force a delay before * strategies can be updated */ interface IEarnStrategyRegistry { /// @notice Thrown when trying to register a strategy that is already registered error StrategyAlreadyRegistered(); /// @notice Thrown when trying to propose a strategy update that has another pending proposal error StrategyAlreadyProposedUpdate(); /// @notice Thrown when trying to propose a strategy update that doesn't have the same asset as the current strategy error AssetMismatch(); /** * @notice Thrown when trying to propose a strategy update that doesn't support at least same tokens as the current * strategy */ error TokensSupportedMismatch(); /** * @notice Thrown when the sender is not the owner of the strategy. */ error UnauthorizedStrategyOwner(); /** * @notice Thrown when the sender is not the strategy ownership receiver. */ error UnauthorizedOwnershipReceiver(); /** * @notice Thrown when trying to register an address that is not an strategy * @param notStrategy The address that was not a strategy */ error AddressIsNotStrategy(IEarnStrategy notStrategy); /** * @notice Thrown when trying to register an strategy that does no report the asset as first token * @param invalidStrategy The object that was not a valid strategy */ error AssetIsNotFirstToken(IEarnStrategy invalidStrategy); /** * @notice Thrown when trying to cancel a proposed update, but no new strategy has been proposed for the strategy id * @param strategyId The strategy id without a proposed update */ error MissingStrategyProposedUpdate(StrategyId strategyId); /** * @notice Thrown when trying to confirm the proposed update before the delay has passed * @param strategyId The strategy id to update */ error StrategyUpdateBeforeDelay(StrategyId strategyId); /** * @notice Thrown when the migration data doesn't match the expected one * @param strategyId The strategy id to update */ error MigrationDataMismatch(StrategyId strategyId); /// @notice Thrown when trying to propose a strategy ownership transfer that has a pending proposal error StrategyOwnershipTransferAlreadyProposed(); /// @notice Thrown when trying to cancel a proposed strategy ownership transfer without a pending proposal error StrategyOwnershipTransferWithoutPendingProposal(); /// @notice Thrown when trying to confirm the proposed update with lower balances than the current one error ProposedStrategyBalancesAreLowerThanCurrentStrategy(); /** * @notice Emitted when a new strategy is registered * @param owner The strategy's owner * @param strategyId The strategy id * @param strategy The strategy */ event StrategyRegistered(address owner, StrategyId strategyId, IEarnStrategy strategy); /** * @notice Emitted when a new strategy is proposed * @param strategyId The strategy id * @param newStrategy The strategy * @param migrationData Data to be used as part of the migration */ event StrategyUpdateProposed(StrategyId strategyId, IEarnStrategy newStrategy, bytes migrationData); /** * @notice Emitted when a new strategy is updated * @param strategyId The strategy id * @param newStrategy The strategy */ event StrategyUpdated(StrategyId strategyId, IEarnStrategy newStrategy); /** * @notice Emitted when a proposed update is canceled * @param strategyId The strategy id * @param strategy The strategy we were going to update the id to */ event StrategyUpdateCanceled(StrategyId strategyId, IEarnStrategy strategy); /** * @notice Emitted when a proposed strategy ownership transfer is proposed * @param strategyId The strategy id * @param newOwner The proposed new owner */ event StrategyOwnershipTransferProposed(StrategyId strategyId, address newOwner); /** * @notice Emitted when a proposed strategy ownership transfer is canceled * @param strategyId The strategy id * @param receiver The canceled receiver */ event StrategyOwnershipTransferCanceled(StrategyId strategyId, address receiver); /** * @notice Emitted when a strategy ownership is transferred * @param strategyId The strategy id * @param newOwner The new owner */ event StrategyOwnershipTransferred(StrategyId strategyId, address newOwner); /** * @notice Returns the delay (in seconds) necessary to execute a proposed strategy update * @return The delay (in seconds) necessary to execute a proposed strategy update */ // slither-disable-next-line naming-convention function STRATEGY_UPDATE_DELAY() external pure returns (uint256); /** * @notice Returns the strategy registered to the given id * @param strategyId The id to check * @return The registered strategy, or the zero address if none is registered */ function getStrategy(StrategyId strategyId) external view returns (IEarnStrategy); /** * @notice Returns the id that is assigned to the strategy * @param strategy The strategy to check * @return The assigned if, or zero if it hasn't been assigned */ function assignedId(IEarnStrategy strategy) external view returns (StrategyId); /** * @notice Returns any proposed update for the given strategy id * @param strategyId The id to check for proposed updates * @return newStrategy The new strategy * @return executableAt When the update will be executable */ function proposedUpdate(StrategyId strategyId) external view returns (IEarnStrategy newStrategy, uint96 executableAt, bytes32 migrationDataHash); /** * @notice Returns any proposed ownership transfer for the given strategy id * @param strategyId The id to check for proposed ownership transfers * @return newOwner The new owner, or the zero address if no transfer was proposed */ function proposedOwnershipTransfer(StrategyId strategyId) external view returns (address newOwner); /** * @notice Returns the number of registered strategies * @return The number of registered strategies */ function totalRegistered() external view returns (uint256); /** * @notice Registers a new strategy * @dev The strategy must report the asset as the first token * The strategy can't be associated to another id * The new strategy must support the expected interface. * @param firstOwner The strategy's owner * @param strategy The strategy to register * @return The id assigned to the new strategy */ function registerStrategy(address firstOwner, IEarnStrategy strategy) external returns (StrategyId); /** * @notice Returns the strategy's owner to the given id * @param strategyId The id to check * @return The owner of the strategy, or the zero address if none is registered */ function owner(StrategyId strategyId) external view returns (address); /** * @notice Proposes an ownership transfer. Must be accepted by the new owner * @dev Can only be called by the strategy's owner * @param strategyId The id of the strategy to change ownership of * @param newOwner The new owner */ function proposeOwnershipTransfer(StrategyId strategyId, address newOwner) external; /** * @notice Cancels an ownership transfer * @dev Can only be called by the strategy's owner * @param strategyId The id of the strategy that was being transferred */ function cancelOwnershipTransfer(StrategyId strategyId) external; /** * @notice Accepts an ownership transfer, and updates the owner by doing so * @dev Can only be called by the strategy's new owner * @param strategyId The id of the strategy that was being transferred */ function acceptOwnershipTransfer(StrategyId strategyId) external; /** * @notice Proposes a strategy update * @dev Can only be called by the strategy's owner. * The strategy must report the asset as the first token * The new strategy can't be associated to another id, neither can it be in the process of being associated to * another id. * The new strategy must support the expected interface. * The new strategy must have the same asset as the strategy it's replacing. * The new strategy must support the same tokens as the strategy it's replacing. It may also support new ones. * @param strategyId The strategy to update * @param newStrategy The new strategy to associate to the id * @param migrationData Data to be used as part of the migration */ function proposeStrategyUpdate( StrategyId strategyId, IEarnStrategy newStrategy, bytes calldata migrationData ) external; /** * @notice Cancels a strategy update * @dev Can only be called by the strategy's owner * @param strategyId The strategy that was being updated */ function cancelStrategyUpdate(StrategyId strategyId) external; /** * @notice Updates a strategy, after the delay has passed * @dev The migration data must be the same as the ones passed during the proposal * @param strategyId The strategy to update * @param migrationData Data to be used as part of the migration */ function updateStrategy(StrategyId strategyId, bytes calldata migrationData) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; import { IEarnVault } from "./IEarnVault.sol"; /** * @title The interface for generating a description for a position in a Earn Vault * @notice Contracts that implement this interface must return a base64 JSON with the entire description */ interface IEarnNFTDescriptor { /** * @notice Generates a positions's description, both the JSON and the image inside * @param vault The address of the Earn Vault * @param positionId The position id * @return description The position's description */ function tokenURI(IEarnVault vault, uint256 positionId) external view returns (string memory description); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.8; type SpecialWithdrawalCode is uint256; using { equals as ==, notEquals as != } for SpecialWithdrawalCode global; // slither-disable-next-line dead-code function equals(SpecialWithdrawalCode code1, SpecialWithdrawalCode code2) pure returns (bool) { return SpecialWithdrawalCode.unwrap(code1) == SpecialWithdrawalCode.unwrap(code2); } // slither-disable-next-line dead-code function notEquals(SpecialWithdrawalCode code1, SpecialWithdrawalCode code2) pure returns (bool) { return SpecialWithdrawalCode.unwrap(code1) != SpecialWithdrawalCode.unwrap(code2); } /** * @title Special withdrawals * @notice There are some cases where we might want to perform a special withdrawal. For example, if a * token only supports a delayed withdrawal, we might want to withdraw the farm token directly and * sell it on the market, instead of waiting for the normal process. * Since each strategy could support different types of withdrawals, we need to define a "protocol" * on how to execute and interpret each of them. Input and output are encoded as bytes, in here we'll * specify how to encode/decode them. */ library SpecialWithdrawal { /* * Withdraws the asset's farm token directly, by specifying the amount of farm tokens to withdraw */ SpecialWithdrawalCode internal constant WITHDRAW_ASSET_FARM_TOKEN_BY_AMOUNT = SpecialWithdrawalCode.wrap(0); /* * Withdraws the asset's farm token directly, by specifying the equivalent in terms of the asset */ SpecialWithdrawalCode internal constant WITHDRAW_ASSET_FARM_TOKEN_BY_ASSET_AMOUNT = SpecialWithdrawalCode.wrap(1); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
{ "remappings": [ "@prb/test/=node_modules/@prb/test/src/", "ds-test/=node_modules/ds-test/src/", "forge-std/=node_modules/forge-std/src/", "@clones/=node_modules/clones/src/", "src/=src/", "@openzeppelin/=node_modules/@openzeppelin/", "@balmy/nft-permissions/=node_modules/@balmy/nft-permissions/src/", "@balmy/nft-permissions-test/=node_modules/@balmy/nft-permissions/test/", "@balmy/earn-core/=node_modules/@balmy/earn-core/src/", "@balmy/earn-core-test/=node_modules/@balmy/earn-core/test/", "@forta/firewall/=node_modules/@forta/firewall/src/" ], "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": { "node_modules/@forta/firewall/src/Quantization.sol": { "Quantization": "0x7A9FE945B4eaC7693E10fcD4F510f97a295307A4" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IEarnVault","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdapterDuplicated","type":"error"},{"inputs":[],"name":"AdapterMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[],"name":"UnauthorizedWithdrawal","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"adapter","type":"address"}],"name":"DelayedWithdrawalRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"positionId","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawn","type":"uint256"}],"name":"WithdrawnFunds","type":"event"},{"inputs":[],"name":"VAULT","outputs":[{"internalType":"contract IEarnVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"}],"name":"allPositionFunds","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"estimatedPending","type":"uint256[]"},{"internalType":"uint256[]","name":"withdrawable","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"estimatedPendingFunds","outputs":[{"internalType":"uint256","name":"pendingFunds","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"registerDelayedWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"withdrawn","type":"uint256"},{"internalType":"uint256","name":"stillPending","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"withdrawableFunds","outputs":[{"internalType":"uint256","name":"funds","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c080604052346100d557602081611628803803809161001f82856100ec565b8339810103126100d557516001600160a01b038116908181036100d557608052604051635faf45bd60e01b815290602090829060049082905afa9081156100e1575f916100a1575b5060a0526040516115049081610124823960805181818161027b015281816105a901528181610c7a0152610f27015260a051816102390152f35b90506020813d6020116100d9575b816100bc602093836100ec565b810103126100d5575160ff811681036100d5575f610067565b5f80fd5b3d91506100af565b6040513d5f823e3d90fd5b601f909101601f19168101906001600160401b0382119082101761010f57604052565b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c80632cedc68a14610f4b578063411557d114610efb5780635452666714610c13578063ac9650d8146109d9578063b263b7cc1461054e578063b460af94146101c55763b57f84ac14610066575f80fd5b346101af5760406003193601126101af5760043561008261109b565b905f90805f526020925f845260405f209173ffffffffffffffffffffffffffffffffffffffff928383165f52855260405f20915f9160019360015b6100cb578787604051908152f35b835f5280885260405f20604051906100e2826110f1565b549060ff8a89841692838152019260a01c161515825280610107575b505115156100bd565b6040517fb57f84ac0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff8616602482015295989195908a90829060449082905afa80156101ba5787915f91610183575b5061017a919261117b565b9701935f6100fe565b8092508b8092503d83116101b3575b61019c818361113a565b810103126101af5751869061017a61016f565b5f80fd5b503d610192565b6040513d5f823e3d90fd5b346101af5760606003193601126101af576101de61109b565b73ffffffffffffffffffffffffffffffffffffffff60443516604435036101af575f806040517f823abfd9000000000000000000000000000000000000000000000000000000008152600435600482015233602482015260ff7f000000000000000000000000000000000000000000000000000000000000000016604482015260208160648173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9081156101ba575f9161051f575b50156104f5576004355f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff84165f5260205260405f205f905f9160015b610383575b82811061036d575050507f5d59f11b58458fbcad377ef1f5dd5c53b158cacf770d418be4a655f3a1e625a2608060409473ffffffffffffffffffffffffffffffffffffffff865191600435835216602082015273ffffffffffffffffffffffffffffffffffffffff6044351686820152846060820152a182519182526020820152f35b806001915f52826020525f6040812055016102ea565b825f528160205260405f206040519061039b826110f1565b5473ffffffffffffffffffffffffffffffffffffffff811680835260a082901c60ff16151560208401526103d6575b506020015115156102e5565b604080517fb460af94000000000000000000000000000000000000000000000000000000008152600480359082015273ffffffffffffffffffffffffffffffffffffffff8a81166024830152604480358216908301529798979396939092839160649183915f91165af19586156101ba575f915f976104b6575b5061045f61046592889261117b565b9761117b565b94610476575b6001019260206103ca565b9060018082602093850361048f575b019291505061046b565b6104b173ffffffffffffffffffffffffffffffffffffffff8851168288611363565b610485565b965090506040863d6040116104ed575b816104d36040938361113a565b810103126101af578551602090960151959061045f610450565b3d91506104c6565b60046040517f60b39bc5000000000000000000000000000000000000000000000000000000008152fd5b610541915060203d602011610547575b610539818361113a565b8101906112d1565b846102ab565b503d61052f565b346101af5760206003193601126101af576040517ff7a95a9e00000000000000000000000000000000000000000000000000000000815260043560048201525f8160248173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa9081156101ba575f916108a7575b5080516105e581611282565b906105ef81611282565b905f5b81811061067a575050604051928392606084016060855282518091526020608086019301905f5b81811061064b5750505081610639918561064795940360208701526110be565b9083820360408501526110be565b0390f35b825173ffffffffffffffffffffffffffffffffffffffff16855287965060209485019490920191600101610619565b73ffffffffffffffffffffffffffffffffffffffff61069c8287959697611207565b51166004355f525f60205260405f20815f5260205260405f205f9060015b6106cd57505050600101939291936105f2565b815f528060205260405f20604051906106e5826110f1565b5460ff73ffffffffffffffffffffffffffffffffffffffff82169182845260a01c161515602083015280610720575b506020015115156106ba565b6040517f2cedc68a000000000000000000000000000000000000000000000000000000008152600480359082015273ffffffffffffffffffffffffffffffffffffffff8616602482015291939190602090829060449082905afa80156101ba575f90610873575b61079c9150610796878b611207565b5161117b565b6107a6868a611207565b5282516040517fb57f84ac000000000000000000000000000000000000000000000000000000008152600480359082015273ffffffffffffffffffffffffffffffffffffffff8681166024830152909160209183916044918391165afa9081156101ba578a87915f9361083b575b506001926107966020959361082893611207565b610832888d611207565b52019290610714565b925050506020813d60201161086b575b816108586020938361113a565b810103126101af5751858a610828610814565b3d915061084b565b506020813d60201161089f575b8161088d6020938361113a565b810103126101af5761079c9051610787565b3d9150610880565b90503d805f833e6108b8818361113a565b8101906080818303126101af5780519167ffffffffffffffff928381116101af5782019281601f850112156101af5783516108f2816111b5565b94610900604051968761113a565b81865260208087019260051b820101908482116101af57602001915b8183106109ac5750505060208301519081116101af57820181601f820112156101af5780519060208061094e846111b5565b61095b604051918261113a565b848152019260051b8201019283116101af57602001905b82821061099c5750505060608161098e60406109959401611248565b5001611261565b50816105d9565b8151815260209182019101610972565b825173ffffffffffffffffffffffffffffffffffffffff811681036101af5781526020928301920161091c565b6020806003193601126101af576004359067ffffffffffffffff8083116101af57366023840112156101af578260040135908082116101af57600560243684831b87018201116101af57610a2e8492946111b5565b93610a3c604051958661113a565b828552610a48836111b5565b967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0809801875f5b828110610c03575050505f917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b858110610b3f5789898960405191808301818452825180915260408401918060408360051b8701019401925f965b838810610ade5786860387f35b9091929394838080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08b6001960301875285601f838c518051918291828752018686015e5f85828601015201160101970193019701969093929193610ad1565b8481831b84010135848112156101af5783019085820135918883116101af576044908181019380360385136101af57610b77816111cd565b91610b85604051938461113a565b8183528d8301938236920101116101af575f838e93828585829660019b610bde9a37830101525190305af43d15610bfa573d610bc0816111cd565b90610bce604051928361113a565b81525f81933d92013e5b30611464565b610be8828b611207565b52610bf3818a611207565b5001610aa3565b60609150610bd8565b6060898201830152899101610a70565b346101af5760406003193601126101af57600435610c2f61109b565b9073ffffffffffffffffffffffffffffffffffffffff6040517f95c0465a000000000000000000000000000000000000000000000000000000008152826004820152604081602481857f0000000000000000000000000000000000000000000000000000000000000000165afa9081156101ba575f905f92610ea6575b506bffffffffffffffffffffffff1615610e2757811690604051907f01ffc9a70000000000000000000000000000000000000000000000000000000082527ff2670b730000000000000000000000000000000000000000000000000000000060048301526020918281602481875afa9081156101ba575f91610e89575b5015610e2757604051907f034db2350000000000000000000000000000000000000000000000000000000082528282602481848a16978860048301525afa9182156101ba575f92610e51575b5033911603610e2757825f525f815260405f20915f525260405f2091610d9b33846112e9565b90610dfd577fd4ad436bd7ca727f4928e74a79db1cf6060d563e6a7b27b9703c1348756a781c93610dcd913391611363565b6040805192835273ffffffffffffffffffffffffffffffffffffffff9190911660208301523390820152606090a1005b60046040517fd176fd8c000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa9cd67ae000000000000000000000000000000000000000000000000000000008152fd5b9091508281813d8311610e82575b610e69818361113a565b810103126101af575181811681036101af579086610d75565b503d610e5f565b610ea09150833d851161054757610539818361113a565b86610d29565b9150506040813d604011610ef3575b81610ec26040938361113a565b810103126101af576bffffffffffffffffffffffff610eec6020610ee584611248565b9301611261565b9190610cac565b3d9150610eb5565b346101af575f6003193601126101af57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101af5760406003193601126101af57600435610f6761109b565b905f90805f526020925f845260405f209173ffffffffffffffffffffffffffffffffffffffff928383165f52855260405f20915f9160019360015b610fb0578787604051908152f35b835f5280885260405f2060405190610fc7826110f1565b549060ff8a89841692838152019260a01c161515825280610fec575b50511515610fa2565b6040517f2cedc68a0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff8616602482015295989195908a90829060449082905afa80156101ba5787915f91611068575b5061105f919261117b565b97019389610fe3565b8092508b8092503d8311611094575b611081818361113a565b810103126101af5751869061105f611054565b503d611077565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101af57565b9081518082526020808093019301915f5b8281106110dd575050505090565b8351855293810193928101926001016110cf565b6040810190811067ffffffffffffffff82111761110d57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761110d57604052565b9190820180921161118857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff811161110d5760051b60200190565b67ffffffffffffffff811161110d57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b805182101561121b5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b51906bffffffffffffffffffffffff821682036101af57565b519073ffffffffffffffffffffffffffffffffffffffff821682036101af57565b9061128c826111b5565b611299604051918261113a565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06112c782946111b5565b0190602036910137565b908160209103126101af575180151581036101af5790565b5f929160015b6112fa5750505f9190565b835f5260208281526040805f20905190611313826110f1565b549073ffffffffffffffffffffffffffffffffffffffff9060ff8284169384835260a01c16151593849101528316811461135657156112ef5793600101936112ef565b5050505090506001905f90565b91816113ee575b60405192611377846110f1565b73ffffffffffffffffffffffffffffffffffffffff809216845260208401925f84525f5260205260405f209251167fffffffffffffffffffffff00000000000000000000000000000000000000000074ff000000000000000000000000000000000000000084549351151560a01b16921617179055565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201828111611188575f528260205260405f20740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff82541617905561136a565b906114a3575080511561147957805190602001fd5b60046040517fd6bda275000000000000000000000000000000000000000000000000000000008152fd5b815115806114fb575b6114b4575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156114ac5600000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c80632cedc68a14610f4b578063411557d114610efb5780635452666714610c13578063ac9650d8146109d9578063b263b7cc1461054e578063b460af94146101c55763b57f84ac14610066575f80fd5b346101af5760406003193601126101af5760043561008261109b565b905f90805f526020925f845260405f209173ffffffffffffffffffffffffffffffffffffffff928383165f52855260405f20915f9160019360015b6100cb578787604051908152f35b835f5280885260405f20604051906100e2826110f1565b549060ff8a89841692838152019260a01c161515825280610107575b505115156100bd565b6040517fb57f84ac0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff8616602482015295989195908a90829060449082905afa80156101ba5787915f91610183575b5061017a919261117b565b9701935f6100fe565b8092508b8092503d83116101b3575b61019c818361113a565b810103126101af5751869061017a61016f565b5f80fd5b503d610192565b6040513d5f823e3d90fd5b346101af5760606003193601126101af576101de61109b565b73ffffffffffffffffffffffffffffffffffffffff60443516604435036101af575f806040517f823abfd9000000000000000000000000000000000000000000000000000000008152600435600482015233602482015260ff7f000000000000000000000000000000000000000000000000000000000000000116604482015260208160648173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461165afa9081156101ba575f9161051f575b50156104f5576004355f525f60205260405f2073ffffffffffffffffffffffffffffffffffffffff84165f5260205260405f205f905f9160015b610383575b82811061036d575050507f5d59f11b58458fbcad377ef1f5dd5c53b158cacf770d418be4a655f3a1e625a2608060409473ffffffffffffffffffffffffffffffffffffffff865191600435835216602082015273ffffffffffffffffffffffffffffffffffffffff6044351686820152846060820152a182519182526020820152f35b806001915f52826020525f6040812055016102ea565b825f528160205260405f206040519061039b826110f1565b5473ffffffffffffffffffffffffffffffffffffffff811680835260a082901c60ff16151560208401526103d6575b506020015115156102e5565b604080517fb460af94000000000000000000000000000000000000000000000000000000008152600480359082015273ffffffffffffffffffffffffffffffffffffffff8a81166024830152604480358216908301529798979396939092839160649183915f91165af19586156101ba575f915f976104b6575b5061045f61046592889261117b565b9761117b565b94610476575b6001019260206103ca565b9060018082602093850361048f575b019291505061046b565b6104b173ffffffffffffffffffffffffffffffffffffffff8851168288611363565b610485565b965090506040863d6040116104ed575b816104d36040938361113a565b810103126101af578551602090960151959061045f610450565b3d91506104c6565b60046040517f60b39bc5000000000000000000000000000000000000000000000000000000008152fd5b610541915060203d602011610547575b610539818361113a565b8101906112d1565b846102ab565b503d61052f565b346101af5760206003193601126101af576040517ff7a95a9e00000000000000000000000000000000000000000000000000000000815260043560048201525f8160248173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461165afa9081156101ba575f916108a7575b5080516105e581611282565b906105ef81611282565b905f5b81811061067a575050604051928392606084016060855282518091526020608086019301905f5b81811061064b5750505081610639918561064795940360208701526110be565b9083820360408501526110be565b0390f35b825173ffffffffffffffffffffffffffffffffffffffff16855287965060209485019490920191600101610619565b73ffffffffffffffffffffffffffffffffffffffff61069c8287959697611207565b51166004355f525f60205260405f20815f5260205260405f205f9060015b6106cd57505050600101939291936105f2565b815f528060205260405f20604051906106e5826110f1565b5460ff73ffffffffffffffffffffffffffffffffffffffff82169182845260a01c161515602083015280610720575b506020015115156106ba565b6040517f2cedc68a000000000000000000000000000000000000000000000000000000008152600480359082015273ffffffffffffffffffffffffffffffffffffffff8616602482015291939190602090829060449082905afa80156101ba575f90610873575b61079c9150610796878b611207565b5161117b565b6107a6868a611207565b5282516040517fb57f84ac000000000000000000000000000000000000000000000000000000008152600480359082015273ffffffffffffffffffffffffffffffffffffffff8681166024830152909160209183916044918391165afa9081156101ba578a87915f9361083b575b506001926107966020959361082893611207565b610832888d611207565b52019290610714565b925050506020813d60201161086b575b816108586020938361113a565b810103126101af5751858a610828610814565b3d915061084b565b506020813d60201161089f575b8161088d6020938361113a565b810103126101af5761079c9051610787565b3d9150610880565b90503d805f833e6108b8818361113a565b8101906080818303126101af5780519167ffffffffffffffff928381116101af5782019281601f850112156101af5783516108f2816111b5565b94610900604051968761113a565b81865260208087019260051b820101908482116101af57602001915b8183106109ac5750505060208301519081116101af57820181601f820112156101af5780519060208061094e846111b5565b61095b604051918261113a565b848152019260051b8201019283116101af57602001905b82821061099c5750505060608161098e60406109959401611248565b5001611261565b50816105d9565b8151815260209182019101610972565b825173ffffffffffffffffffffffffffffffffffffffff811681036101af5781526020928301920161091c565b6020806003193601126101af576004359067ffffffffffffffff8083116101af57366023840112156101af578260040135908082116101af57600560243684831b87018201116101af57610a2e8492946111b5565b93610a3c604051958661113a565b828552610a48836111b5565b967fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0809801875f5b828110610c03575050505f917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b858110610b3f5789898960405191808301818452825180915260408401918060408360051b8701019401925f965b838810610ade5786860387f35b9091929394838080837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08b6001960301875285601f838c518051918291828752018686015e5f85828601015201160101970193019701969093929193610ad1565b8481831b84010135848112156101af5783019085820135918883116101af576044908181019380360385136101af57610b77816111cd565b91610b85604051938461113a565b8183528d8301938236920101116101af575f838e93828585829660019b610bde9a37830101525190305af43d15610bfa573d610bc0816111cd565b90610bce604051928361113a565b81525f81933d92013e5b30611464565b610be8828b611207565b52610bf3818a611207565b5001610aa3565b60609150610bd8565b6060898201830152899101610a70565b346101af5760406003193601126101af57600435610c2f61109b565b9073ffffffffffffffffffffffffffffffffffffffff6040517f95c0465a000000000000000000000000000000000000000000000000000000008152826004820152604081602481857f00000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461165afa9081156101ba575f905f92610ea6575b506bffffffffffffffffffffffff1615610e2757811690604051907f01ffc9a70000000000000000000000000000000000000000000000000000000082527ff2670b730000000000000000000000000000000000000000000000000000000060048301526020918281602481875afa9081156101ba575f91610e89575b5015610e2757604051907f034db2350000000000000000000000000000000000000000000000000000000082528282602481848a16978860048301525afa9182156101ba575f92610e51575b5033911603610e2757825f525f815260405f20915f525260405f2091610d9b33846112e9565b90610dfd577fd4ad436bd7ca727f4928e74a79db1cf6060d563e6a7b27b9703c1348756a781c93610dcd913391611363565b6040805192835273ffffffffffffffffffffffffffffffffffffffff9190911660208301523390820152606090a1005b60046040517fd176fd8c000000000000000000000000000000000000000000000000000000008152fd5b60046040517fa9cd67ae000000000000000000000000000000000000000000000000000000008152fd5b9091508281813d8311610e82575b610e69818361113a565b810103126101af575181811681036101af579086610d75565b503d610e5f565b610ea09150833d851161054757610539818361113a565b86610d29565b9150506040813d604011610ef3575b81610ec26040938361113a565b810103126101af576bffffffffffffffffffffffff610eec6020610ee584611248565b9301611261565b9190610cac565b3d9150610eb5565b346101af575f6003193601126101af57602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461168152f35b346101af5760406003193601126101af57600435610f6761109b565b905f90805f526020925f845260405f209173ffffffffffffffffffffffffffffffffffffffff928383165f52855260405f20915f9160019360015b610fb0578787604051908152f35b835f5280885260405f2060405190610fc7826110f1565b549060ff8a89841692838152019260a01c161515825280610fec575b50511515610fa2565b6040517f2cedc68a0000000000000000000000000000000000000000000000000000000081526004810185905273ffffffffffffffffffffffffffffffffffffffff8616602482015295989195908a90829060449082905afa80156101ba5787915f91611068575b5061105f919261117b565b97019389610fe3565b8092508b8092503d8311611094575b611081818361113a565b810103126101af5751869061105f611054565b503d611077565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036101af57565b9081518082526020808093019301915f5b8281106110dd575050505090565b8351855293810193928101926001016110cf565b6040810190811067ffffffffffffffff82111761110d57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761110d57604052565b9190820180921161118857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b67ffffffffffffffff811161110d5760051b60200190565b67ffffffffffffffff811161110d57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b805182101561121b5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b51906bffffffffffffffffffffffff821682036101af57565b519073ffffffffffffffffffffffffffffffffffffffff821682036101af57565b9061128c826111b5565b611299604051918261113a565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06112c782946111b5565b0190602036910137565b908160209103126101af575180151581036101af5790565b5f929160015b6112fa5750505f9190565b835f5260208281526040805f20905190611313826110f1565b549073ffffffffffffffffffffffffffffffffffffffff9060ff8284169384835260a01c16151593849101528316811461135657156112ef5793600101936112ef565b5050505090506001905f90565b91816113ee575b60405192611377846110f1565b73ffffffffffffffffffffffffffffffffffffffff809216845260208401925f84525f5260205260405f209251167fffffffffffffffffffffff00000000000000000000000000000000000000000074ff000000000000000000000000000000000000000084549351151560a01b16921617179055565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201828111611188575f528260205260405f20740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff82541617905561136a565b906114a3575080511561147957805190602001fd5b60046040517fd6bda275000000000000000000000000000000000000000000000000000000008152fd5b815115806114fb575b6114b4575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156114ac56
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461
-----Decoded View---------------
Arg [0] : vault (address): 0x58E5d76Fbbd7E1b51F0fC0F66B7734E108be0461
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000058e5d76fbbd7e1b51f0fc0f66b7734e108be0461
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.