Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 317 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 18671491 | 511 days ago | IN | 0 ETH | 0.00500744 | ||||
Withdraw | 18671052 | 511 days ago | IN | 0 ETH | 0.00448744 | ||||
Progress Epoch | 18663572 | 512 days ago | IN | 0 ETH | 0.00838485 | ||||
Unlock | 18620760 | 518 days ago | IN | 0 ETH | 0.00386568 | ||||
Unlock | 18585826 | 523 days ago | IN | 0 ETH | 0.00669896 | ||||
Withdraw | 18299218 | 563 days ago | IN | 0 ETH | 0.00076512 | ||||
Progress Epoch | 18290846 | 564 days ago | IN | 0 ETH | 0.00204996 | ||||
Unlock | 18288741 | 564 days ago | IN | 0 ETH | 0.00061734 | ||||
Withdraw | 18288734 | 564 days ago | IN | 0 ETH | 0.00053468 | ||||
Withdraw | 18285741 | 565 days ago | IN | 0 ETH | 0.00125998 | ||||
Withdraw | 18275099 | 566 days ago | IN | 0 ETH | 0.00063544 | ||||
Progress Epoch | 18264080 | 568 days ago | IN | 0 ETH | 0.00543859 | ||||
Withdraw | 18237989 | 571 days ago | IN | 0 ETH | 0.00074552 | ||||
Unlock | 18237233 | 572 days ago | IN | 0 ETH | 0.00090093 | ||||
Withdraw | 18237228 | 572 days ago | IN | 0 ETH | 0.00084499 | ||||
Withdraw | 18235058 | 572 days ago | IN | 0 ETH | 0.00176855 | ||||
Progress Epoch | 18228245 | 573 days ago | IN | 0 ETH | 0.00321677 | ||||
Unlock | 18224144 | 573 days ago | IN | 0 ETH | 0.00064827 | ||||
Withdraw | 18224133 | 573 days ago | IN | 0 ETH | 0.00072681 | ||||
Unlock | 18220120 | 574 days ago | IN | 0 ETH | 0.00131284 | ||||
Withdraw | 18220116 | 574 days ago | IN | 0 ETH | 0.00170898 | ||||
Unlock | 18220096 | 574 days ago | IN | 0 ETH | 0.00207047 | ||||
Withdraw | 18220092 | 574 days ago | IN | 0 ETH | 0.00190314 | ||||
Withdraw | 18193995 | 578 days ago | IN | 0 ETH | 0.00074708 | ||||
Withdraw | 18192548 | 578 days ago | IN | 0 ETH | 0.00123228 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x00000089...c16Ccd583 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
RPVault
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//.██████..███████.███████.██.....██████..██████...██████. //.██...██.██......██......██.....██...██.██...██.██....██ //.██████..█████...█████...██.....██████..██████..██....██ //.██...██.██......██......██.....██......██...██.██....██ //.██...██.███████.██......██.....██......██...██..██████. // SPDX-License-Identifier: MIT pragma solidity ^0.8.14; import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol"; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { ERC20 } from "solmate/tokens/ERC20.sol"; import { Auth, Authority } from "solmate/auth/Auth.sol"; import { ERC4626Accounting } from "./ERC4626Accounting.sol"; import { IVaultConfig } from "./interfaces/IVaultConfig.sol"; /// @title RPVault /// @notice epoch-based fund management contract that uses ERC4626 accounting logic. /// @dev in this version, the contract does not actually use ERC4626 base functions. /// @dev all vault tokens are stored in-contract, owned by farmer address. /// @dev all assets are sent to farmer address each epoch change; /// @dev except for: stored fee, pending withdrawals, & pending deposits. /// @author mathdroid (https://github.com/mathdroid) contract RPVault is ERC4626Accounting, Auth { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /// ██████████████ vault metadata ████████████████████████████████████████ /// @notice aum = **external** assets under management uint256 public aum = 0; /// @notice aumCap = maximum aum allowed to be stored in the contract uint256 public aumCap = 0; /// @notice epoch = period of time where aum is being managed uint256 public epoch = 0; /// @notice farmer = administrative address, responsible for managing aum /// @dev the address where funds will go from/to the contract address public immutable farmer; /// @notice managementBlocksDuration = number of blocks where farmer can make amendments to the contract /// @dev this is to prevent mistakes when progressing epoch uint256 public managementBlocksDuration = 6000; // avg block time is 15 seconds, so this is ~24 hours /// @notice vault config contract address public vaultConfigAddress; /// ██████████████ fees ███████████████████████████████████████████████████ /// @notice isFeeEnabled = flag to enable/disable fees bool public isFeeEnabled = false; /// @notice feeDistributor = address to receive fees from the contract address public feeDistributor; /// @notice managementFeeBps = management fee in basis points per second /// @dev only charged when delta AUM is positive in an epoch /// @dev management fee = (assetsExternalEnd - assetsExternalStart) * managementFeeBps / 1e5 uint256 public managementFeeBps = 2000; /// @notice entry/exit fees are charged when a user enters/exits the contract uint256 public entryFeeBps = 100; /// @notice entry/exit fees are charged when a user enters/exits the contract uint256 public exitFeeBps = 100; /// @notice storedFee = the amount of stored fee in the contract uint256 public storedFee; /// @notice helper for fee calculation uint256 private constant BASIS = 10000; /// ██████████████ vault state per epoch ██████████████████████████████████ struct VaultState { /// @dev starting AUM this epoch uint256 assetsExternalStart; /// @dev assets deposited by users during this epoch uint256 assetsToDeposit; /// @dev shares unlocked during this epoch uint256 sharesToRedeem; /// @dev the number of external AUM at the end of epoch (after fees) uint256 assetsExternalEnd; /// @dev management fee captured this epoch. maybe 0 if delta AUM <= 0 /// @dev managementFee + assetsExternalEnd == aum input by farmer uint256 managementFee; /// @dev total vault tokens supply /// @dev no difference start/end of the epoch uint256 totalSupply; /// @dev last block number where farmer can edit the aum /// @dev only farmer can interact with contract before this blocknumber uint256 lastManagementBlock; } /// @notice vaultState = array of vault states per epoch mapping(uint256 => VaultState) public vaultStates; /// ██████████████ user balances ██████████████████████████████████████████ struct VaultUser { /// @dev assets currently deposited, not yet included in aum /// @dev should be zeroed after epoch change (shares minted) uint256 assetsDeposited; /// @dev last epoch where user deposited assets uint256 epochLastDeposited; /// @dev glorified `balanceOf` uint256 vaultShares; /// @dev shares to be unlocked next epoch uint256 sharesToRedeem; /// @dev the epoch where user can start withdrawing the unlocked shares /// @dev use this epoch's redemption rate (aum/totalSupply) to calculate the amount of assets to be withdrawn uint256 epochToRedeem; } /// @notice vaultUsers = array of user balances per address mapping(address => VaultUser) public vaultUsers; /// ██████████████ errors █████████████████████████████████████████████████ /// ░░░░░░░░░░░░░░ internal ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice transaction will result in zero shares given error DepositReturnsZeroShares(); /// @notice transaction will result in zero assets given error RedeemReturnsZeroAssets(); /// ░░░░░░░░░░░░░░ epoch ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice vault is still initializing error VaultIsInitializing(); /// @notice vault has been initialized error VaultAlreadyInitialized(); /// ░░░░░░░░░░░░░░ management phase ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice farmer function called outside management phase error OnlyAtManagementPhase(); /// @notice public function called during management phase error OnlyOutsideManagementPhase(); /// ░░░░░░░░░░░░░░ farmer ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice wrong aum cap value (lower than current aum, etc) error AumCapInvalid(); /// @notice wrong ending aum value (infinite growth) error AumInvalid(); /// @notice farmer asset allowance insufficient error FarmerInsufficientAllowance(); /// @notice farmer asset balance insufficient error FarmerInsufficientBalance(); /// ░░░░░░░░░░░░░░ fee ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice error setting fee config error FeeSettingsInvalid(); /// @notice stored fees = 0; error FeeIsZero(); /// ░░░░░░░░░░░░░░ deposit ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice deposit > aum cap error DepositExceedsAumCap(); /// @notice deposit negated by config contract error DepositRequirementsNotMet(); /// @notice deposit fees larger than sent amount error DepositFeeExceedsAssets(); /// @notice has a pending withdrawal error DepositBlockedByWithdrawal(); /// ░░░░░░░░░░░░░░ unlock ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice has a pending withdrawal already error UnlockBlockedByWithdrawal(); /// @notice invalid amount e.g. 0 error UnlockSharesAmountInvalid(); /// @notice error UnlockExceedsShareBalance(); /// ░░░░░░░░░░░░░░ withdraw ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice not the epoch to withdraw error WithdrawNotAvailableYet(); /// ██████████████ events █████████████████████████████████████████████████ /// @notice user events event UserDeposit(address indexed user, uint256 amount); event UserUnlock(address indexed user, uint256 amount); event UserWithdraw(address indexed user, address withdrawalAddress, uint256 amount); /// @notice vault events event EpochEnd(uint256 epoch, uint256 endingAssets); event EpochUpdated(uint256 epoch, uint256 endingAssets); event AumCapUpdated(uint256 aumCap); /// @notice fee events event StoredFeeSent(uint256 amount); event FeeUpdated(bool isFeeEnabled, uint256 entryFee, uint256 exitFee, uint256 managementFee); event FeeReceiverUpdated(address feeDistributor); /// ██████████████ modifiers ██████████████████████████████████████████████ /// requiresAuth -> from solmate/Auth modifier onlyEpochZero() { if (epoch != 0) revert VaultAlreadyInitialized(); _; } modifier exceptEpochZero() { if (epoch < 1) revert VaultIsInitializing(); _; } modifier onlyManagementPhase() { if (!isManagementPhase()) { revert OnlyAtManagementPhase(); } _; } modifier exceptManagementPhase() { if (isManagementPhase()) { revert OnlyOutsideManagementPhase(); } _; } modifier canDeposit(address _user, uint256 _assets) { if (userHasPendingWithdrawal(_user)) { revert DepositBlockedByWithdrawal(); } // cap must be higher than current AUM + pending deposit + incoming deposit if (_assets + getEffectiveAssets() > aumCap) { revert DepositExceedsAumCap(); } if (vaultConfigAddress != address(0) && !IVaultConfig(vaultConfigAddress).canDeposit(_user, _assets)) { revert DepositRequirementsNotMet(); } _; } modifier canUnlock(address _user, uint256 _shares) { if (_shares < 1) revert UnlockSharesAmountInvalid(); if (msg.sender != _user) { uint256 allowed = allowance[_user][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[_user][msg.sender] = allowed - _shares; } if (userHasPendingWithdrawal(_user)) revert UnlockBlockedByWithdrawal(); _; } modifier canWithdraw(address _user) { if (!userHasPendingWithdrawal(_user)) { revert WithdrawNotAvailableYet(); } _; } modifier updatesPendingDeposit(address _user) { updatePendingDepositState(_user); _; } /// ██████████████ ERC4626 ████████████████████████████████████████████████ /// ░░░░░░░░░░░░░░ constructor ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice create an RPVault /// @param _name token name, also used as vault name in the UI, omitting `Token` postfix /// @param _symbol token symbol, also used as vault symbol in the UI /// @param _farmer farmer address, responsible for managing aum /// @param _feeDistributor address to receive fees from the contract /// @param _underlying asset to be used as underlying asset for the vault /// @param _vaultConfig contract address to be used as vault config contract. if 0x0, default config will be used constructor( string memory _name, string memory _symbol, address _farmer, address _feeDistributor, address _underlying, address _vaultConfig ) ERC4626Accounting(ERC20(_underlying), _name, _symbol) Auth(_farmer, Authority(address(0))) { farmer = _farmer; feeDistributor = _feeDistributor; vaultConfigAddress = _vaultConfig; } /// @notice Get the amount of productive underlying tokens /// @dev used at self deposits/redeems at epoch change /// @return aum, total external productive assets function totalAssets() public view override returns (uint256) { return aum; } /// ██████████████ farmer functions ███████████████████████████████████████ /* farmer's actions: - [x] starts vault with initial settings - [x] progress epoch - [x] update aum (management phase only) - [x] end management phase (management phase only) - [x] update aum cap - [x] enable/disable fees - [x] update fees - [x] update fee distributor - [x] update vault config address */ /// @notice starts the vault with a custom initial aum /// @dev in most cases, initial aum = 0 /// @param _initialExternalAsset initial aum, must be held by farmer /// @param _aumCap maximum asset that can be stored function startVault(uint256 _initialExternalAsset, uint256 _aumCap) external onlyEpochZero requiresAuth { if (_aumCap < _initialExternalAsset) { revert AumCapInvalid(); } if (_initialExternalAsset != 0) { uint256 initialShare = _selfDeposit(_initialExternalAsset); vaultUsers[msg.sender].vaultShares = initialShare; } aumCap = _aumCap; epoch = 1; vaultStates[epoch].assetsExternalStart = aum; vaultStates[epoch].totalSupply = totalSupply; vaultStates[epoch].lastManagementBlock = block.number; emit EpochEnd(0, aum); } /// @notice Increment epoch from n to (n + 1) /// @dev goes to management phase after this function is called /// @param _assetsExternalEndBeforeFees current external asset (manual counting by farmer) /// @return newAUM (external asset) function progressEpoch(uint256 _assetsExternalEndBeforeFees) public requiresAuth exceptEpochZero returns (uint256) { // end epoch n ( bool shouldTransferToFarm, uint256 totalAssetsToTransfer, bool shouldDepositDelta, uint256 deltaAssets, uint256 managementFee, uint256 assetsExternalEnd ) = previewProgress(_assetsExternalEndBeforeFees, epoch); storedFee += managementFee; vaultStates[epoch].managementFee = managementFee; aum = assetsExternalEnd; vaultStates[epoch].assetsExternalEnd = assetsExternalEnd; emit EpochEnd(epoch, aum); epoch++; // start epoch n + 1 // transfer assets if (totalAssetsToTransfer > 0) { if (shouldTransferToFarm) { // if there are assets to be transferred to the farm, do it transferAssetToFarmer(totalAssetsToTransfer); } else { // transfer back to contract // msg.sender is farmer address transferAssetToContract(totalAssetsToTransfer); } } // self deposit/redeem delta if (deltaAssets > 0) { if (shouldDepositDelta) { // self-deposit, update aum _selfDeposit(deltaAssets); } else { // self-redeem, update aum _selfRedeem(convertToShares(deltaAssets)); } } // if new aum is higher than the cap, increase the cap if (aum > aumCap) { aumCap = aum; emit AumCapUpdated(aumCap); } // update vault state vaultStates[epoch].assetsExternalStart = aum; vaultStates[epoch].totalSupply = totalSupply; vaultStates[epoch].lastManagementBlock = block.number + managementBlocksDuration; return aum; } /// @notice amends last epoch's aum update /// @dev callable at management phase only /// @param _assetsExternalEndBeforeFees current external asset (manual counting by farmer) /// @return newAUM (external asset) // solhint-disable-next-line code-complexity function editAUM(uint256 _assetsExternalEndBeforeFees) public onlyManagementPhase requiresAuth returns (uint256 newAUM) { uint256 lastEpoch = epoch - 1; uint256 lastAssetsExternalEnd = vaultStates[lastEpoch].assetsExternalEnd; uint256 lastManagementFee = vaultStates[lastEpoch].managementFee; uint256 lastTotalSupply = vaultStates[lastEpoch].totalSupply; if (_assetsExternalEndBeforeFees == lastAssetsExternalEnd + lastManagementFee) { // no change in aum return lastAssetsExternalEnd; } ( bool didTransferToFarm, uint256 totalAssetsTransferred, // bool didDepositDelta, , , , ) = previewProgress(lastAssetsExternalEnd + lastManagementFee, lastEpoch); /// @dev rather than saving gas by combining these into 1 transfers but with overflow handling, we do it in 2 /// @dev gas is paid by farmer (upkeep) // revert transfers if (totalAssetsTransferred > 0) { if (didTransferToFarm) { // revert transferAssetToContract(totalAssetsTransferred); } else { transferAssetToFarmer(totalAssetsTransferred); } } // // revert deposit/redeem using latest rate, update aum automatically if (totalSupply > lastTotalSupply) { _burn(address(this), totalSupply - lastTotalSupply); } if (totalSupply < lastTotalSupply) { _mint(address(this), lastTotalSupply - totalSupply); } // /// @dev by this point, aum should be the same as last epoch's aum storedFee -= lastManagementFee; epoch = lastEpoch; return progressEpoch(_assetsExternalEndBeforeFees); } /// @notice ends management phase, allow users to deposit/unlock/withdraw function endManagementPhase() public requiresAuth onlyManagementPhase { vaultStates[epoch].lastManagementBlock = block.number; } /// @notice change AUM cap /// @param _aumCap new AUM cap function updateAumCap(uint256 _aumCap) public requiresAuth { if (aumCap < getEffectiveAssets()) { revert AumCapInvalid(); } aumCap = _aumCap; } /// @notice toggle fees on/off /// @param _isFeeEnabled true to enable fees, false to disable fees function setIsFeeEnabled(bool _isFeeEnabled) public requiresAuth { if (isFeeEnabled == _isFeeEnabled) { revert FeeSettingsInvalid(); } isFeeEnabled = _isFeeEnabled; } /// @notice update fees function setFees( uint256 _managementFeeBps, uint256 _entryFeeBps, uint256 _exitFeeBps ) public requiresAuth { if (_managementFeeBps > BASIS || _entryFeeBps > BASIS || _exitFeeBps > BASIS) { revert FeeSettingsInvalid(); } managementFeeBps = _managementFeeBps; entryFeeBps = _entryFeeBps; exitFeeBps = _exitFeeBps; } /// @notice update fee distributor function setFeeDistributor(address _feeDistributor) public requiresAuth { if (_feeDistributor == address(0)) { revert FeeSettingsInvalid(); } feeDistributor = _feeDistributor; } function setVaultConfigAddress(address _vaultConfigAddress) public requiresAuth { vaultConfigAddress = _vaultConfigAddress; } /// ██████████████ user functions █████████████████████████████████████████ /* A user can only do: - [x] deposit (not to be confused with ERC4626 deposit) - minimum/maximum rule set in the vaultConfig contract - [x] unlock - [x] withdraw (not to be confused with ERC4626 withdraw) */ /// ░░░░░░░░░░░░░░ deposit ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice a user stores assets in the contract to enter in the next epoch /// @dev funds should be withdrawable before epoch progresses /// @dev actual share minting happens at the epoch progression /// @dev share minting uses next epoch's starting exchange rate function deposit(uint256 _assets) external exceptEpochZero exceptManagementPhase returns (uint256) { return deposit(_assets, msg.sender); } function deposit(uint256 _assets, address _for) public exceptEpochZero exceptManagementPhase canDeposit(_for, _assets) updatesPendingDeposit(_for) returns (uint256) { uint256 depositFee = getDepositFee(_assets, _for); if (depositFee >= _assets) { revert DepositFeeExceedsAssets(); } uint256 netAssets = _assets - depositFee; storedFee += depositFee; /// last deposit epoch = 0 /// assetDeposited = 0 vaultUsers[_for].epochLastDeposited = epoch; vaultUsers[_for].assetsDeposited += netAssets; // update vault state vaultStates[epoch].assetsToDeposit += netAssets; // transfer asset to vault asset.safeTransferFrom(msg.sender, address(this), _assets); emit UserDeposit(_for, netAssets); return netAssets; } /// ░░░░░░░░░░░░░░ unlock (withdraw 1/2) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice unlock _shares for withdrawal at next available epoch function unlock(uint256 _shares) external exceptEpochZero exceptManagementPhase returns (uint256) { return unlock(_shares, msg.sender); } function unlock(uint256 _shares, address _owner) public exceptEpochZero exceptManagementPhase canUnlock(_owner, _shares) updatesPendingDeposit(_owner) returns (uint256) { // updatePendingDepositState(msg.sender); if (vaultUsers[_owner].vaultShares < vaultUsers[_owner].sharesToRedeem + _shares) { revert UnlockExceedsShareBalance(); } vaultUsers[_owner].sharesToRedeem += _shares; vaultUsers[_owner].epochToRedeem = epoch + 1; vaultStates[epoch].sharesToRedeem += _shares; emit UserUnlock(_owner, _shares); return _shares; } /// ░░░░░░░░░░░░░░ finalize (withdraw 2/2) ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ /// @notice withdraw all available asset for user function withdraw() external exceptEpochZero exceptManagementPhase returns (uint256) { return withdraw(msg.sender); } function withdraw(address _to) public exceptEpochZero exceptManagementPhase canWithdraw(msg.sender) updatesPendingDeposit(msg.sender) returns (uint256) { (uint256 totalAssetValue, uint256 withdrawalFee) = getWithdrawalAmount(msg.sender); vaultUsers[msg.sender].vaultShares -= vaultUsers[msg.sender].sharesToRedeem; vaultUsers[msg.sender].sharesToRedeem = 0; vaultUsers[msg.sender].epochToRedeem = 0; storedFee += withdrawalFee; if (withdrawalFee == totalAssetValue) { // @dev for really small values, we can't afford to lose precision return 0; } uint256 transferValue = totalAssetValue - withdrawalFee; asset.transfer(_to, transferValue); emit UserWithdraw(msg.sender, _to, transferValue); return transferValue; } /// ██████████████ public functions ███████████████████████████████████████ /* public functions: - [x] preview funds flow from/to contract next epoch - [x] check if user can deposit/unlock/withdraw - [x] send stored fees to fee distributor - [x] get maximum deposit amount */ /// @notice preview funds flow from/to contract next epoch /// @dev assets to transfer = deltaAssets - managementFee /// @dev sign shows direction of transfer (true = to farm, false = to contract) /// @param _assetsExternalEndBeforeFees amount of external aum before fees /// @return shouldTransferToFarm direction of funds to transfer /// @return totalAssetsToTransfer amount of assets to transfer /// @return shouldDepositDelta true if deltaAssets should be deposited, false if deltaAssets should be redeemed /// @return deltaAssets amount of assets to deposit/redeem /// @return managementFee amount of management fee for next epoch /// @return assetsExternalEnd amount of vault ending aum. assetsExternalEnd = _assetsExternalEndBeforeFees - fees function previewProgress(uint256 _assetsExternalEndBeforeFees) public view returns ( bool shouldTransferToFarm, uint256 totalAssetsToTransfer, bool shouldDepositDelta, uint256 deltaAssets, uint256 managementFee, uint256 assetsExternalEnd ) { return previewProgress(_assetsExternalEndBeforeFees, epoch); } function previewProgress(uint256 _assetsExternalEndBeforeFees, uint256 _epoch) public view returns ( bool shouldTransferToFarm, uint256 totalAssetsToTransfer, bool shouldDepositDelta, uint256 deltaAssets, uint256 managementFee, uint256 assetsExternalEnd ) { uint256 epochTotalSupply = _epoch == epoch ? totalSupply : vaultStates[_epoch].totalSupply; uint256 assetsExternalStart = vaultStates[_epoch].assetsExternalStart; uint256 assetsToDeposit = vaultStates[_epoch].assetsToDeposit; uint256 sharesToRedeem = vaultStates[_epoch].sharesToRedeem; if (assetsExternalStart == 0 && _assetsExternalEndBeforeFees > 0) { revert AumInvalid(); } managementFee = getManagementFee(assetsExternalStart, _assetsExternalEndBeforeFees); assetsExternalEnd = _assetsExternalEndBeforeFees - managementFee; /// @dev at 0 supply, rate is 1:1 uint256 redeemAssetValue = epochTotalSupply == 0 ? sharesToRedeem : sharesToRedeem.mulDivDown(assetsExternalEnd, epochTotalSupply); /// @dev if true, the delta (deltaAssets) will be used in selfDeposit. /// @dev if false, the delta will be "soft-used" in selfRedeem(shares); shouldDepositDelta = assetsToDeposit > redeemAssetValue; deltaAssets = shouldDepositDelta ? assetsToDeposit - redeemAssetValue : redeemAssetValue - assetsToDeposit; if (shouldDepositDelta) { // if deposit is bigger, transfer to farm // subtract by management fee if (managementFee > deltaAssets) { // reverse if fee > delta totalAssetsToTransfer = managementFee - deltaAssets; shouldTransferToFarm = false; } else { totalAssetsToTransfer = deltaAssets - managementFee; shouldTransferToFarm = true; } } else { // if redeem value is bigger, transfer to contract // add management fee totalAssetsToTransfer = deltaAssets + managementFee; shouldTransferToFarm = false; } return ( shouldTransferToFarm, totalAssetsToTransfer, shouldDepositDelta, deltaAssets, managementFee, assetsExternalEnd ); } function isManagementPhase() public view returns (bool) { return block.number <= vaultStates[epoch].lastManagementBlock; } /// @notice sends stored fee to fee distributor function sendFee() public exceptManagementPhase { if (storedFee == 0) { revert FeeIsZero(); } uint256 amount = storedFee; storedFee = 0; asset.transfer(feeDistributor, amount); emit StoredFeeSent(storedFee); } /// @notice get maximum deposit amount function getMaxDeposit() public view returns (uint256) { return aumCap - getEffectiveAssets(); } /// @notice preview deposit on epoch function previewDepositEpoch(uint256 _assets, uint256 _epoch) public view returns (uint256) { if (vaultStates[_epoch].totalSupply == 0 || vaultStates[_epoch].assetsExternalStart == 0) { return _assets; } return _assets.mulDivDown(vaultStates[_epoch].totalSupply, vaultStates[_epoch].assetsExternalStart); } /// ██████████████ internals ██████████████████████████████████████████████ // TODO: internalize before deploy /// @notice self-deposit, uses ERC4626 calculations, without actual transfer /// @dev updates AUM /// @param _assets number of assets to deposit /// @return shares minted function _selfDeposit(uint256 _assets) internal returns (uint256) { uint256 shares; if ((shares = previewDeposit(_assets)) == 0) revert DepositReturnsZeroShares(); _mint(address(this), shares); aum += _assets; emit Deposit(msg.sender, address(this), _assets, shares); return shares; } /// @notice self-redeem, uses ERC4626 calculations, without actual transfer /// @dev updates AUM /// @param _shares number of shares to redeem /// @return assets value of burned shares function _selfRedeem(uint256 _shares) internal returns (uint256) { uint256 assets; // Check for rounding error since we round down in previewRedeem. if ((assets = previewRedeem(_shares)) == 0) revert RedeemReturnsZeroAssets(); _burn(address(this), _shares); aum -= assets; emit Withdraw(msg.sender, address(this), address(this), assets, _shares); return assets; } /// @notice calculate management fee based on aum change /// @param _assetsExternalStart assets at start of epoch /// @param _assetsExternalEndBeforeFees assets at end of epoch /// @return managementFee management fees in asset function getManagementFee(uint256 _assetsExternalStart, uint256 _assetsExternalEndBeforeFees) internal view returns (uint256) { if (!isFeeEnabled) { return 0; } return (_assetsExternalEndBeforeFees > _assetsExternalStart && managementFeeBps > 0) ? managementFeeBps.mulDivUp(_assetsExternalEndBeforeFees - _assetsExternalStart, BASIS) : 0; } function transferAssetToFarmer(uint256 _assets) internal returns (bool) { return asset.transfer(farmer, _assets); } function transferAssetToContract(uint256 _assets) internal { if (asset.allowance(msg.sender, address(this)) < _assets) { revert FarmerInsufficientAllowance(); } if (asset.balanceOf(msg.sender) < _assets) { revert FarmerInsufficientBalance(); } return asset.safeTransferFrom(msg.sender, address(this), _assets); } function getEffectiveAssets() internal view returns (uint256) { return aum + vaultStates[epoch].assetsToDeposit; } /// @notice update VaultUser's data if they have pending deposits /// @param _user address of the VaultUser /// @dev after this, last deposit epoch = 0, assetDeposited = 0 /// @dev can be manually called function updatePendingDepositState(address _user) public { // @dev check if user has already stored assets if (userHasPendingDeposit(_user)) { // @dev user should already have shares here, let's increment vaultUsers[_user].vaultShares += previewDepositEpoch( vaultUsers[_user].assetsDeposited, vaultUsers[_user].epochLastDeposited + 1 ); vaultUsers[_user].assetsDeposited = 0; vaultUsers[_user].epochLastDeposited = 0; } } /// @notice check if user has pending deposits /// @param _user address of the VaultUser /// @return true if user has pending deposits function userHasPendingDeposit(address _user) public view returns (bool) { uint256 userEpoch = vaultUsers[_user].epochLastDeposited; return userEpoch != 0 && epoch > userEpoch; } /// @notice get deposit fee for user function getDepositFee(uint256 _assets, address _user) public view returns (uint256) { if (vaultConfigAddress != address(0) && IVaultConfig(vaultConfigAddress).isFeeEnabled(_user)) { return _assets.mulDivUp(IVaultConfig(vaultConfigAddress).entryFeeBps(_user), BASIS); } else { return isFeeEnabled ? _assets.mulDivUp(entryFeeBps, BASIS) : 0; } } /// @notice check if a user has pending, unlocked funds to withdraw function userHasPendingWithdrawal(address _user) public view returns (bool) { return vaultUsers[_user].epochToRedeem > 0 && vaultUsers[_user].epochToRedeem <= epoch; } function getStoredValue(address _user) public view returns (uint256 userAssetValue) { VaultUser memory user = vaultUsers[_user]; uint256 userShares = user.vaultShares; if (userHasPendingDeposit(_user)) { // shares has been minted, user state not yet updated userShares += previewDepositEpoch(user.assetsDeposited, user.epochLastDeposited + 1); } else { // still currently pending (no minted shares yet) userAssetValue += user.assetsDeposited; } userAssetValue += convertToAssets(userShares); } function getWithdrawalFee(uint256 _assets, address _user) public view returns (uint256) { if (vaultConfigAddress != address(0) && IVaultConfig(vaultConfigAddress).isFeeEnabled(_user)) { return _assets.mulDivUp(IVaultConfig(vaultConfigAddress).exitFeeBps(_user), BASIS); } else { return isFeeEnabled ? _assets.mulDivUp(exitFeeBps, BASIS) : 0; } } function getWithdrawalAmount(address _owner) public view returns (uint256, uint256) { if (!userHasPendingWithdrawal(_owner)) return (0, 0); uint256 epochToRedeem = vaultUsers[_owner].epochToRedeem; uint256 sharesToRedeem = vaultUsers[_owner].sharesToRedeem; uint256 assetsExternalStart = vaultStates[epochToRedeem].assetsExternalStart; uint256 totalSupplyAtRedeem = vaultStates[epochToRedeem].totalSupply; if (assetsExternalStart == 0 || totalSupplyAtRedeem == 0) { return (0, 0); } uint256 totalAssetValue = sharesToRedeem.mulDivDown( vaultStates[epochToRedeem].assetsExternalStart, vaultStates[epochToRedeem].totalSupply ); uint256 fee = getWithdrawalFee(totalAssetValue, _owner); return (totalAssetValue, fee); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { // Start off with z at 1. z := 1 // Used below to help find a nearby power of 2. let y := x // Find the lowest power of 2 that is at least sqrt(x). if iszero(lt(y, 0x100000000000000000000000000000000)) { y := shr(128, y) // Like dividing by 2 ** 128. z := shl(64, z) // Like multiplying by 2 ** 64. } if iszero(lt(y, 0x10000000000000000)) { y := shr(64, y) // Like dividing by 2 ** 64. z := shl(32, z) // Like multiplying by 2 ** 32. } if iszero(lt(y, 0x100000000)) { y := shr(32, y) // Like dividing by 2 ** 32. z := shl(16, z) // Like multiplying by 2 ** 16. } if iszero(lt(y, 0x10000)) { y := shr(16, y) // Like dividing by 2 ** 16. z := shl(8, z) // Like multiplying by 2 ** 8. } if iszero(lt(y, 0x100)) { y := shr(8, y) // Like dividing by 2 ** 8. z := shl(4, z) // Like multiplying by 2 ** 4. } if iszero(lt(y, 0x10)) { y := shr(4, y) // Like dividing by 2 ** 4. z := shl(2, z) // Like multiplying by 2 ** 2. } if iszero(lt(y, 0x8)) { // Equivalent to 2 ** z. z := shl(1, z) } // Shifting right by 1 is like dividing by 2. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // Compute a rounded down version of z. let zRoundDown := div(x, z) // If zRoundDown is smaller, use it. if lt(zRoundDown, z) { z := zRoundDown } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) abstract contract Auth { event OwnerUpdated(address indexed user, address indexed newOwner); event AuthorityUpdated(address indexed user, Authority indexed newAuthority); address public owner; Authority public authority; constructor(address _owner, Authority _authority) { owner = _owner; authority = _authority; emit OwnerUpdated(msg.sender, _owner); emit AuthorityUpdated(msg.sender, _authority); } modifier requiresAuth() virtual { require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); _; } function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be // aware that this makes protected functions uncallable even to the owner if the authority is out of order. return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; } function setAuthority(Authority newAuthority) public virtual { // We check if the caller is the owner first because we want to ensure they can // always swap out the authority even if it's reverting or using up a lot of gas. require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig)); authority = newAuthority; emit AuthorityUpdated(msg.sender, newAuthority); } function setOwner(address newOwner) public virtual requiresAuth { owner = newOwner; emit OwnerUpdated(msg.sender, newOwner); } } /// @notice A generic interface for a contract which provides authorization data to an Auth instance. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) interface Authority { function canCall( address user, address target, bytes4 functionSig ) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.4 <0.9.0; import { ERC20 } from "solmate/tokens/ERC20.sol"; import { SafeTransferLib } from "solmate/utils/SafeTransferLib.sol"; import { FixedPointMathLib } from "solmate/utils/FixedPointMathLib.sol"; /// @notice Minimal ERC4626 tokenized Vault implementation. /// @dev derived from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/mixins/ERC4626.sol) abstract contract ERC4626Accounting is ERC20 { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ ERC20 public immutable asset; constructor( ERC20 _asset, string memory _name, string memory _symbol ) ERC20(_name, _symbol, _asset.decimals()) { asset = _asset; } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LOGIC //////////////////////////////////////////////////////////////*/ /* None! Ta da! */ /*////////////////////////////////////////////////////////////// ACCOUNTING LOGIC //////////////////////////////////////////////////////////////*/ function totalAssets() public view virtual returns (uint256); function convertToShares(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); } function convertToAssets(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); } function previewDeposit(uint256 assets) public view virtual returns (uint256) { return convertToShares(assets); } function previewMint(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); } function previewWithdraw(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); } function previewRedeem(uint256 shares) public view virtual returns (uint256) { return convertToAssets(shares); } }
//.██████..███████.███████.██.....██████..██████...██████. //.██...██.██......██......██.....██...██.██...██.██....██ //.██████..█████...█████...██.....██████..██████..██....██ //.██...██.██......██......██.....██......██...██.██....██ //.██...██.███████.██......██.....██......██...██..██████. // SPDX-License-Identifier: MIT pragma solidity ^0.8.14; interface IVaultConfig { function canDeposit(address _user, uint256 _assets) external view returns (bool); function isFeeEnabled(address _user) external view returns (bool); function entryFeeBps(address _user) external view returns (uint256); function exitFeeBps(address _user) external view returns (uint256); /// @dev management fee is the same for everyone // function managementFeeBps() external view returns (uint256); }
{ "remappings": [ "ds-test/=lib/solmate/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solmate/=lib/solmate/src/", "src/=src/", "test/=test/", "script/=script/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_farmer","type":"address"},{"internalType":"address","name":"_feeDistributor","type":"address"},{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"address","name":"_vaultConfig","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AumCapInvalid","type":"error"},{"inputs":[],"name":"AumInvalid","type":"error"},{"inputs":[],"name":"DepositBlockedByWithdrawal","type":"error"},{"inputs":[],"name":"DepositExceedsAumCap","type":"error"},{"inputs":[],"name":"DepositFeeExceedsAssets","type":"error"},{"inputs":[],"name":"DepositRequirementsNotMet","type":"error"},{"inputs":[],"name":"DepositReturnsZeroShares","type":"error"},{"inputs":[],"name":"FarmerInsufficientAllowance","type":"error"},{"inputs":[],"name":"FarmerInsufficientBalance","type":"error"},{"inputs":[],"name":"FeeIsZero","type":"error"},{"inputs":[],"name":"FeeSettingsInvalid","type":"error"},{"inputs":[],"name":"OnlyAtManagementPhase","type":"error"},{"inputs":[],"name":"OnlyOutsideManagementPhase","type":"error"},{"inputs":[],"name":"RedeemReturnsZeroAssets","type":"error"},{"inputs":[],"name":"UnlockBlockedByWithdrawal","type":"error"},{"inputs":[],"name":"UnlockExceedsShareBalance","type":"error"},{"inputs":[],"name":"UnlockSharesAmountInvalid","type":"error"},{"inputs":[],"name":"VaultAlreadyInitialized","type":"error"},{"inputs":[],"name":"VaultIsInitializing","type":"error"},{"inputs":[],"name":"WithdrawNotAvailableYet","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"aumCap","type":"uint256"}],"name":"AumCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endingAssets","type":"uint256"}],"name":"EpochEnd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endingAssets","type":"uint256"}],"name":"EpochUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeDistributor","type":"address"}],"name":"FeeReceiverUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isFeeEnabled","type":"bool"},{"indexed":false,"internalType":"uint256","name":"entryFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exitFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"managementFee","type":"uint256"}],"name":"FeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StoredFeeSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UserDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UserUnlock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawalAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"UserWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aumCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_for","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetsExternalEndBeforeFees","type":"uint256"}],"name":"editAUM","outputs":[{"internalType":"uint256","name":"newAUM","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endManagementPhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entryFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeDistributor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getDepositFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getStoredValue","outputs":[{"internalType":"uint256","name":"userAssetValue","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getWithdrawalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getWithdrawalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFeeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isManagementPhase","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managementBlocksDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managementFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"previewDepositEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetsExternalEndBeforeFees","type":"uint256"}],"name":"previewProgress","outputs":[{"internalType":"bool","name":"shouldTransferToFarm","type":"bool"},{"internalType":"uint256","name":"totalAssetsToTransfer","type":"uint256"},{"internalType":"bool","name":"shouldDepositDelta","type":"bool"},{"internalType":"uint256","name":"deltaAssets","type":"uint256"},{"internalType":"uint256","name":"managementFee","type":"uint256"},{"internalType":"uint256","name":"assetsExternalEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetsExternalEndBeforeFees","type":"uint256"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"previewProgress","outputs":[{"internalType":"bool","name":"shouldTransferToFarm","type":"bool"},{"internalType":"uint256","name":"totalAssetsToTransfer","type":"uint256"},{"internalType":"bool","name":"shouldDepositDelta","type":"bool"},{"internalType":"uint256","name":"deltaAssets","type":"uint256"},{"internalType":"uint256","name":"managementFee","type":"uint256"},{"internalType":"uint256","name":"assetsExternalEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assetsExternalEndBeforeFees","type":"uint256"}],"name":"progressEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sendFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeDistributor","type":"address"}],"name":"setFeeDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_managementFeeBps","type":"uint256"},{"internalType":"uint256","name":"_entryFeeBps","type":"uint256"},{"internalType":"uint256","name":"_exitFeeBps","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isFeeEnabled","type":"bool"}],"name":"setIsFeeEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultConfigAddress","type":"address"}],"name":"setVaultConfigAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialExternalAsset","type":"uint256"},{"internalType":"uint256","name":"_aumCap","type":"uint256"}],"name":"startVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"storedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"unlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"}],"name":"unlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aumCap","type":"uint256"}],"name":"updateAumCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"updatePendingDepositState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"userHasPendingDeposit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"userHasPendingWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultConfigAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vaultStates","outputs":[{"internalType":"uint256","name":"assetsExternalStart","type":"uint256"},{"internalType":"uint256","name":"assetsToDeposit","type":"uint256"},{"internalType":"uint256","name":"sharesToRedeem","type":"uint256"},{"internalType":"uint256","name":"assetsExternalEnd","type":"uint256"},{"internalType":"uint256","name":"managementFee","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"uint256","name":"lastManagementBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaultUsers","outputs":[{"internalType":"uint256","name":"assetsDeposited","type":"uint256"},{"internalType":"uint256","name":"epochLastDeposited","type":"uint256"},{"internalType":"uint256","name":"vaultShares","type":"uint256"},{"internalType":"uint256","name":"sharesToRedeem","type":"uint256"},{"internalType":"uint256","name":"epochToRedeem","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103e65760003560e01c80637a9e5e4b1161020a578063c1dbbc3111610125578063d811fcf0116100b8578063ef8b30f711610087578063ef8b30f71461099a578063f1d2ec1d146109ad578063f366d950146109c0578063f70881a3146109d3578063fa37a9ba146109e657600080fd5b8063d811fcf014610922578063dc4a5bff14610949578063dd62ed3e1461095c578063ecda74cf1461098757600080fd5b8063cec10c11116100f4578063cec10c11146108e0578063d49e271d146108f3578063d4d4be2f146108fc578063d505accf1461090f57600080fd5b8063c1dbbc3114610894578063c6e6f592146108a7578063c7ba9c72146108ba578063ccfc2e8d146108cd57600080fd5b806399f2dda61161019d578063ae39279f1161016c578063ae39279f14610853578063b3d7f6b91461085b578063b6b55f251461086e578063bf7e214f1461088157600080fd5b806399f2dda61461081c578063a4dbc6a814610825578063a5cc958d1461082d578063a9059cbb1461084057600080fd5b80638da5cb5b116101d95780638da5cb5b146107e5578063900cf0cf146107f8578063907e98cd1461080157806395d89b411461081457600080fd5b80637a9e5e4b146107305780637ecebe0014610743578063808dd5eb14610763578063849efb711461078057600080fd5b8063344de0ac11610305578063578334ee1161029857806361bc2e331161026757806361bc2e33146106ce5780636e553f65146106e15780636ea97367146106f457806370a082311461070757806371634e321461072757600080fd5b8063578334ee1461069657806357b17a521461069f5780635a157a25146106a85780636198e339146106bb57600080fd5b80633ccfd60b116102d45780633ccfd60b146106405780634cdad5061461064857806351cff8d91461065b57806356582bf91461066e57600080fd5b8063344de0ac146105f55780633644e515146106085780633813c35a1461061057806338d52e0f1461061957600080fd5b80630d43e8ad1161037d57806318160ddd1161034c57806318160ddd146105585780631c4ad9151461056157806323b872dd146105a9578063313ce567146105bc57600080fd5b80630d43e8ad146104865780630e66dc69146104b1578063119435a4146104c557806313af40351461054557600080fd5b8063095ea7b3116103b9578063095ea7b31461043d5780630a28a477146104605780630ab51bac146104735780630b38bed91461047c57600080fd5b806301e1d114146103eb57806306fdde031461040257806307a2d13a146104175780630807ac571461042a575b600080fd5b6008545b6040519081526020015b60405180910390f35b61040a6109f9565b6040516103f99190612ed8565b6103ef610425366004612f2d565b610a87565b6103ef610438366004612f46565b610ab5565b61045061044b366004612f7d565b610b14565b60405190151581526020016103f9565b6103ef61046e366004612f2d565b610b80565b6103ef60085481565b610484610ba1565b005b600d54610499906001600160a01b031681565b6040516001600160a01b0390911681526020016103f9565b600c5461045090600160a01b900460ff1681565b6105106104d3366004612f2d565b6012602052600090815260409020805460018201546002830154600384015460048501546005860154600690960154949593949293919290919087565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016103f9565b610484610553366004612fa9565b610c2b565b6103ef60025481565b61057461056f366004612f2d565b610ca9565b6040805196151587526020870195909552921515938501939093526060840152608083019190915260a082015260c0016103f9565b6104506105b7366004612fc6565b610cd2565b6105e37f000000000000000000000000000000000000000000000000000000000000000681565b60405160ff90911681526020016103f9565b610484610603366004612fa9565b610db2565b6103ef610e06565b6103ef600e5481565b6104997f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6103ef610e61565b6103ef610656366004612f2d565b610ec4565b6103ef610669366004612fa9565b610ecf565b61068161067c366004612fa9565b6110d2565b604080519283526020830191909152016103f9565b6103ef600f5481565b6103ef60105481565b6103ef6106b6366004612f2d565b611183565b6103ef6106c9366004612f2d565b6112f0565b600c54610499906001600160a01b031681565b6103ef6106ef366004613007565b611354565b610484610702366004612fa9565b6115f8565b6103ef610715366004612fa9565b60036020526000908152604090205481565b6103ef60115481565b61048461073e366004612fa9565b611687565b6103ef610751366004612fa9565b60056020526000908152604090205481565b600a54600090815260126020526040902060060154431115610450565b6107bd61078e366004612fa9565b601360205260009081526040902080546001820154600283015460038401546004909401549293919290919085565b604080519586526020860194909452928401919091526060830152608082015260a0016103f9565b600654610499906001600160a01b031681565b6103ef600a5481565b6103ef61080f366004612fa9565b611771565b61040a611822565b6103ef60095481565b6103ef61182f565b61048461083b366004612f46565b611846565b61045061084e366004612f7d565b6119a8565b610484611a0e565b6103ef610869366004612f2d565b611b45565b6103ef61087c366004612f2d565b611b65565b600754610499906001600160a01b031681565b6103ef6108a2366004613007565b611bc9565b6103ef6108b5366004612f2d565b611cff565b6103ef6108c8366004612f2d565b611d20565b6104846108db366004612fa9565b611f1f565b6104846108ee366004613037565b611f9a565b6103ef600b5481565b61045061090a366004612fa9565b612015565b61048461091d366004613063565b612061565b6104997f0000000000000000000000004457df4a5bccf796662b6374d5947c881cc83ac781565b6104846109573660046130e8565b6122a5565b6103ef61096a366004613105565b600460209081526000928352604080842090915290825290205481565b610574610995366004612f46565b612328565b6103ef6109a8366004612f2d565b612453565b6103ef6109bb366004613007565b61245e565b6104846109ce366004612f2d565b6126a9565b6104506109e1366004612fa9565b61270a565b6103ef6109f4366004613007565b61273a565b60008054610a0690613133565b80601f0160208091040260200160405190810160405280929190818152602001828054610a3290613133565b8015610a7f5780601f10610a5457610100808354040283529160200191610a7f565b820191906000526020600020905b815481529060010190602001808311610a6257829003601f168201915b505050505081565b6002546000908015610aac57610aa7610a9f60085490565b849083612822565b610aae565b825b9392505050565b6000818152601260205260408120600501541580610adf5750600082815260126020526040902054155b15610aeb575081610b0e565b600082815260126020526040902060058101549054610b0b918591612822565b90505b92915050565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610b6f9086815260200190565b60405180910390a350600192915050565b6002546000908015610aac57610aa781610b9960085490565b859190612841565b610bb7336000356001600160e01b03191661286f565b610bdc5760405162461bcd60e51b8152600401610bd39061316d565b60405180910390fd5b600a54600090815260126020526040902060060154431115610c11576040516354a9d44560e01b815260040160405180910390fd5b600a54600090815260126020526040902043600690910155565b610c41336000356001600160e01b03191661286f565b610c5d5760405162461bcd60e51b8152600401610bd39061316d565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a350565b600080600080600080610cbe87600a54612328565b949c939b5091995097509550909350915050565b6001600160a01b03831660009081526004602090815260408083203384529091528120546000198114610d2e57610d0983826131a9565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b03851660009081526003602052604081208054859290610d569084906131a9565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716906000805160206132f483398151915290610d9f9087815260200190565b60405180910390a3506001949350505050565b610dc8336000356001600160e01b03191661286f565b610de45760405162461bcd60e51b8152600401610bd39061316d565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b60007f00000000000000000000000000000000000000000000000000000000000000014614610e3c57610e37612918565b905090565b507fb870d8574d8f3f1ba4f7675cd64f74f3c42de31dc6f1f51d07ae153028ca759b90565b60006001600a541015610e87576040516324875a2960e11b815260040160405180910390fd5b600a546000908152601260205260409020600601544311610ebb576040516335e7b1ad60e01b815260040160405180910390fd5b610e3733610ecf565b6000610b0e82610a87565b60006001600a541015610ef5576040516324875a2960e11b815260040160405180910390fd5b600a546000908152601260205260409020600601544311610f29576040516335e7b1ad60e01b815260040160405180910390fd5b33610f3381612015565b610f50576040516377a59ab560e11b815260040160405180910390fd5b33610f5a816115f8565b600080610f66336110d2565b33600090815260136020526040812060038101546002909101805494965092945092610f939084906131a9565b90915550503360009081526013602052604081206003810182905560040181905560118054839290610fc69084906131c0565b9091555050818103610fdd576000945050506110cb565b6000610fe982846131a9565b60405163a9059cbb60e01b81526001600160a01b038981166004830152602482018390529192507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489091169063a9059cbb906044016020604051808303816000875af115801561105d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108191906131d8565b50604080516001600160a01b03891681526020810183905233917f6985a6dd52aeb8194df40b7af2f362f362440affc39c1314649abc28dbf6b628910160405180910390a2945050505b5050919050565b6000806110de83612015565b6110ed57506000928392509050565b6001600160a01b03831660009081526013602090815260408083206004810154600390910154818552601290935292208054600590910154811580611130575080155b156111445750600096879650945050505050565b60008481526012602052604081208054600590910154611165918691612822565b90506000611173828a611bc9565b9199919850909650505050505050565b600a546000908152601260205260408120600601544311156111b8576040516354a9d44560e01b815260040160405180910390fd5b6111ce336000356001600160e01b03191661286f565b6111ea5760405162461bcd60e51b8152600401610bd39061316d565b60006001600a546111fb91906131a9565b6000818152601260205260409020600381015460048201546005909201549293509161122782846131c0565b8603611237575090949350505050565b60008061124d61124785876131c0565b87612328565b5050505091509150600081111561127d5781156112725761126d816129b2565b61127d565b61127b81612b3f565b505b82600254111561129e5761129e308460025461129991906131a9565b612bf7565b8260025410156112bf576112bf30600254856112ba91906131a9565b612c61565b83601160008282546112d191906131a9565b9091555050600a8690556112e488611d20565b98975050505050505050565b60006001600a541015611316576040516324875a2960e11b815260040160405180910390fd5b600a54600090815260126020526040902060060154431161134a576040516335e7b1ad60e01b815260040160405180910390fd5b610b0e823361245e565b60006001600a54101561137a576040516324875a2960e11b815260040160405180910390fd5b600a5460009081526012602052604090206006015443116113ae576040516335e7b1ad60e01b815260040160405180910390fd5b81836113b982612015565b156113d75760405163915322ab60e01b815260040160405180910390fd5b6009546113e2612cb3565b6113ec90836131c0565b111561140b57604051632d924d8f60e21b815260040160405180910390fd5b600c546001600160a01b0316158015906114975750600c5460405163387777d760e21b81526001600160a01b038481166004830152602482018490529091169063e1dddf5c90604401602060405180830381865afa158015611471573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149591906131d8565b155b156114b55760405163e114baed60e01b815260040160405180910390fd5b836114bf816115f8565b60006114cb878761273a565b90508681106114ed5760405163df19d98160e01b815260040160405180910390fd5b60006114f982896131a9565b9050816011600082825461150d91906131c0565b9091555050600a546001600160a01b038816600090815260136020526040812060018101929092558154839291906115469084906131c0565b9091555050600a546000908152601260205260408120600101805483929061156f9084906131c0565b909155506115aa90506001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481633308b612cd5565b866001600160a01b03167f35db3d768e685509e031bae369804ca7dc6656af739e079f1d3312cadc7b19d8826040516115e591815260200190565b60405180910390a2979650505050505050565b6116018161270a565b15611684576001600160a01b038116600090815260136020526040902080546001918201546116349261043891906131c0565b6001600160a01b0382166000908152601360205260408120600201805490919061165f9084906131c0565b90915550506001600160a01b0381166000908152601360205260408120818155600101555b50565b6006546001600160a01b031633148061171c575060075460405163b700961360e01b81526001600160a01b039091169063b7009613906116db90339030906001600160e01b031960003516906004016131f5565b602060405180830381865afa1580156116f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171c91906131d8565b61172557600080fd5b600780546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b7638998019890600090a350565b6001600160a01b0381166000908152601360209081526040808320815160a081018352815481526001820154938101939093526002810154918301829052600381015460608401526004015460808301526117cb8461270a565b156117f857815160208301516117e791906104389060016131c0565b6117f190826131c0565b9050611807565b815161180490846131c0565b92505b61181081610a87565b61181a90846131c0565b949350505050565b60018054610a0690613133565b6000611839612cb3565b600954610e3791906131a9565b600a54156118675760405163abd5ec5d60e01b815260040160405180910390fd5b61187d336000356001600160e01b03191661286f565b6118995760405162461bcd60e51b8152600401610bd39061316d565b818110156118ba5760405163d6d43aa560e01b815260040160405180910390fd5b81156118e05760006118cb83612d5f565b33600090815260136020526040902060020155505b60098190556001600a819055600854600091825260126020527f71a67924699a20698523213e55fe499d539379d7769cd5567e2c45d583f815a38190556002547f71a67924699a20698523213e55fe499d539379d7769cd5567e2c45d583f815a855437f71a67924699a20698523213e55fe499d539379d7769cd5567e2c45d583f815a9556040517f83fa67c50a5aa34cb3587f7265408d5af55de90232e78550e11a7c22094aa5b79261199c92908252602082015260400190565b60405180910390a15050565b336000908152600360205260408120805483919083906119c99084906131a9565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133906000805160206132f483398151915290610b6f9086815260200190565b600a546000908152601260205260409020600601544311611a42576040516335e7b1ad60e01b815260040160405180910390fd5b601154600003611a65576040516315a6ad9b60e11b815260040160405180910390fd5b601180546000909155600d5460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018390527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489091169063a9059cbb906044016020604051808303816000875af1158015611ae2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b0691906131d8565b507fb4d8a8406f3bc5c93ba2220e6aaf8109c1a327ac49dae93247607983598fc59f601154604051611b3a91815260200190565b60405180910390a150565b6002546000908015610aac57610aa7611b5d60085490565b849083612841565b60006001600a541015611b8b576040516324875a2960e11b815260040160405180910390fd5b600a546000908152601260205260409020600601544311611bbf576040516335e7b1ad60e01b815260040160405180910390fd5b610b0e8233611354565b600c546000906001600160a01b031615801590611c4f5750600c546040516350f0e8fd60e11b81526001600160a01b0384811660048301529091169063a1e1d1fa90602401602060405180830381865afa158015611c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4f91906131d8565b15611cd657600c54604051633c20ee6360e01b81526001600160a01b038481166004830152611ccf921690633c20ee63906024015b602060405180830381865afa158015611ca1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc59190613222565b8490612710612841565b9050610b0e565b600c54600160a01b900460ff16611cee576000611ccf565b601054611ccf908490612710612841565b6002546000908015610aac57610aa781611d1860085490565b859190612822565b6000611d38336000356001600160e01b03191661286f565b611d545760405162461bcd60e51b8152600401610bd39061316d565b6001600a541015611d78576040516324875a2960e11b815260040160405180910390fd5b600080600080600080611d8d88600a54612328565b9550955095509550955095508160116000828254611dab91906131c0565b9091555050600a8054600090815260126020908152604080832060040186905560088590558354835291829020600301849055915481519081529182018390527f83fa67c50a5aa34cb3587f7265408d5af55de90232e78550e11a7c22094aa5b7910160405180910390a1600a8054906000611e268361323b565b90915550508415611e4f578515611e4657611e4085612b3f565b50611e4f565b611e4f856129b2565b8215611e7d578315611e6a57611e6483612d5f565b50611e7d565b611e7b611e7684611cff565b612df2565b505b6009546008541115611ec55760085460098190556040519081527f08a867523cfba7070a600e4f91a0f4794f120cf8c7433ae70c15616acb8945bb9060200160405180910390a15b600854600a805460009081526012602052604080822093909355600254915481529190912060050155600b54611efb90436131c0565b600a5460009081526012602052604090206006015550506008549695505050505050565b611f35336000356001600160e01b03191661286f565b611f515760405162461bcd60e51b8152600401610bd39061316d565b6001600160a01b038116611f785760405163e72c6ebd60e01b815260040160405180910390fd5b600d80546001600160a01b0319166001600160a01b0392909216919091179055565b611fb0336000356001600160e01b03191661286f565b611fcc5760405162461bcd60e51b8152600401610bd39061316d565b612710831180611fdd575061271082115b80611fe9575061271081115b156120075760405163e72c6ebd60e01b815260040160405180910390fd5b600e92909255600f55601055565b6001600160a01b03811660009081526013602052604081206004015415801590610b0e5750600a546001600160a01b038316600090815260136020526040902060040154111592915050565b428410156120b15760405162461bcd60e51b815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610bd3565b600060016120bd610e06565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156121c9573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906121ff5750876001600160a01b0316816001600160a01b0316145b61223c5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa9a4a3a722a960911b6044820152606401610bd3565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6122bb336000356001600160e01b03191661286f565b6122d75760405162461bcd60e51b8152600401610bd39061316d565b801515600c60149054906101000a900460ff1615150361230a5760405163e72c6ebd60e01b815260040160405180910390fd5b600c8054911515600160a01b0260ff60a01b19909216919091179055565b6000806000806000806000600a54881461235357600088815260126020526040902060050154612357565b6002545b6000898152601260205260409020805460018201546002909201549293509182158015612384575060008c115b156123a257604051634ce0b10960e11b815260040160405180910390fd5b6123ac838d612e87565b95506123b8868d6131a9565b9450600084156123d2576123cd828787612822565b6123d4565b815b90508083119850886123ef576123ea83826131a9565b6123f9565b6123f981846131a9565b97508815612433578787111561241e5761241388886131a9565b995060009a50612444565b61242887896131a9565b995060019a50612444565b61243d87896131c0565b995060009a505b50505050509295509295509295565b6000610b0e82611cff565b60006001600a541015612484576040516324875a2960e11b815260040160405180910390fd5b600a5460009081526012602052604090206006015443116124b8576040516335e7b1ad60e01b815260040160405180910390fd5b818360018110156124dc576040516373acfc1d60e11b815260040160405180910390fd5b336001600160a01b0383161461254a576001600160a01b038216600090815260046020908152604080832033845290915290205460001981146125485761252382826131a9565b6001600160a01b03841660009081526004602090815260408083203384529091529020555b505b61255382612015565b1561257157604051634eda1c7f60e11b815260040160405180910390fd5b8361257b816115f8565b6001600160a01b0385166000908152601360205260409020600301546125a29087906131c0565b6001600160a01b03861660009081526013602052604090206002015410156125dd5760405163429d082960e01b815260040160405180910390fd5b6001600160a01b038516600090815260136020526040812060030180548892906126089084906131c0565b9091555050600a5461261b9060016131c0565b6001600160a01b038616600090815260136020908152604080832060040193909355600a54825260129052908120600201805488929061265c9084906131c0565b90915550506040518681526001600160a01b038616907fd1a803266af0ed3665ccaf50b07ec253d106678a2ee563fbc5a0502d702119ae9060200160405180910390a25093949350505050565b6126bf336000356001600160e01b03191661286f565b6126db5760405162461bcd60e51b8152600401610bd39061316d565b6126e3612cb3565b60095410156127055760405163d6d43aa560e01b815260040160405180910390fd5b600955565b6001600160a01b0381166000908152601360205260408120600101548015801590610aae5750600a541192915050565b600c546000906001600160a01b0316158015906127c05750600c546040516350f0e8fd60e11b81526001600160a01b0384811660048301529091169063a1e1d1fa90602401602060405180830381865afa15801561279c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c091906131d8565b156127f957600c5460405163490a847b60e11b81526001600160a01b038481166004830152611ccf92169063921508f690602401611c84565b600c54600160a01b900460ff16612811576000611ccf565b600f54611ccf908490612710612841565b82820281151584158583048514171661283a57600080fd5b0492915050565b82820281151584158583048514171661285957600080fd5b6001826001830304018115150290509392505050565b6007546000906001600160a01b031680158015906128f9575060405163b700961360e01b81526001600160a01b0382169063b7009613906128b8908790309088906004016131f5565b602060405180830381865afa1580156128d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128f991906131d8565b8061181a57506006546001600160a01b03858116911614949350505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f600060405161294a9190613254565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b604051636eb1769f60e11b815233600482015230602482015281907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03169063dd62ed3e90604401602060405180830381865afa158015612a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a429190613222565b1015612a61576040516376dbb4e960e01b815260040160405180910390fd5b6040516370a0823160e01b815233600482015281907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa158015612ac7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aeb9190613222565b1015612b0a5760405163b2a196b160e01b815260040160405180910390fd5b6116846001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333084612cd5565b60405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000004457df4a5bccf796662b6374d5947c881cc83ac781166004830152602482018390526000917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489091169063a9059cbb906044016020604051808303816000875af1158015612bd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e91906131d8565b6001600160a01b03821660009081526003602052604081208054839290612c1f9084906131a9565b90915550506002805482900390556040518181526000906001600160a01b038416906000805160206132f4833981519152906020015b60405180910390a35050565b8060026000828254612c7391906131c0565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481526000805160206132f48339815191529101612c55565b600a54600090815260126020526040812060010154600854610e3791906131c0565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080612d585760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610bd3565b5050505050565b600080612d6b83612453565b905080600003612d8e57604051637a740e7b60e01b815260040160405180910390fd5b612d983082612c61565b8260086000828254612daa91906131c0565b90915550506040805184815260208101839052309133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b600080612dfe83610ec4565b905080600003612e21576040516324a0f01560e21b815260040160405180910390fd5b612e2b3084612bf7565b8060086000828254612e3d91906131a9565b909155505060408051828152602081018590523091829133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a492915050565b600c54600090600160a01b900460ff16612ea357506000610b0e565b8282118015612eb457506000600e54115b612ebf576000610b0b565b610b0b612ecc84846131a9565b600e5490612710612841565b600060208083528351808285015260005b81811015612f0557858101830151858201604001528201612ee9565b81811115612f17576000604083870101525b50601f01601f1916929092016040019392505050565b600060208284031215612f3f57600080fd5b5035919050565b60008060408385031215612f5957600080fd5b50508035926020909101359150565b6001600160a01b038116811461168457600080fd5b60008060408385031215612f9057600080fd5b8235612f9b81612f68565b946020939093013593505050565b600060208284031215612fbb57600080fd5b8135610aae81612f68565b600080600060608486031215612fdb57600080fd5b8335612fe681612f68565b92506020840135612ff681612f68565b929592945050506040919091013590565b6000806040838503121561301a57600080fd5b82359150602083013561302c81612f68565b809150509250929050565b60008060006060848603121561304c57600080fd5b505081359360208301359350604090920135919050565b600080600080600080600060e0888a03121561307e57600080fd5b873561308981612f68565b9650602088013561309981612f68565b95506040880135945060608801359350608088013560ff811681146130bd57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b801515811461168457600080fd5b6000602082840312156130fa57600080fd5b8135610aae816130da565b6000806040838503121561311857600080fd5b823561312381612f68565b9150602083013561302c81612f68565b600181811c9082168061314757607f821691505b60208210810361316757634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6000828210156131bb576131bb613193565b500390565b600082198211156131d3576131d3613193565b500190565b6000602082840312156131ea57600080fd5b8151610aae816130da565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b60006020828403121561323457600080fd5b5051919050565b60006001820161324d5761324d613193565b5060010190565b600080835481600182811c91508083168061327057607f831692505b6020808410820361328f57634e487b7160e01b86526022600452602486fd5b8180156132a357600181146132b8576132e5565b60ff19861689528415158502890196506132e5565b60008a81526020902060005b868110156132dd5781548b8201529085019083016132c4565b505084890196505b50949897505050505050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122030265c565d620ec18d93a75d7fb591d36fcac1ed8706ffd2e0bbb067925b959364736f6c634300080f0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.99998 | 1,141.0384 | $1,141.02 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.