Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 22 from a total of 22 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Safe Deposit ETH | 19828975 | 76 days ago | IN | 0.010489 ETH | 0.00051517 | ||||
Safe Deposit ETH | 19794743 | 80 days ago | IN | 0.033767 ETH | 0.00090155 | ||||
Safe Deposit ETH | 19527407 | 118 days ago | IN | 21.44 ETH | 0.0072721 | ||||
Safe Deposit ETH | 19472994 | 126 days ago | IN | 0.094 ETH | 0.00332962 | ||||
Safe Deposit ETH | 19391064 | 137 days ago | IN | 0.01 ETH | 0.011331 | ||||
Safe Redeem ETH | 18748814 | 227 days ago | IN | 0 ETH | 0.00319546 | ||||
Safe Redeem ETH | 18539223 | 256 days ago | IN | 0 ETH | 0.03537151 | ||||
Safe Redeem ETH | 18399901 | 276 days ago | IN | 0 ETH | 0.00141074 | ||||
Safe Redeem ETH | 18399450 | 276 days ago | IN | 0 ETH | 0.00194982 | ||||
Safe Deposit ETH | 18399428 | 276 days ago | IN | 0.01 ETH | 0.00169231 | ||||
Safe Redeem ETH | 18399420 | 276 days ago | IN | 0 ETH | 0.00175483 | ||||
Safe Deposit ETH | 18399413 | 276 days ago | IN | 0.01 ETH | 0.00190092 | ||||
Redeem ETH | 18397345 | 276 days ago | IN | 0 ETH | 0.00060887 | ||||
Safe Deposit ETH | 18397255 | 276 days ago | IN | 0.01 ETH | 0.00090684 | ||||
Safe Redeem ETH | 18199619 | 304 days ago | IN | 0 ETH | 0.0008713 | ||||
Safe Redeem ETH | 18117085 | 316 days ago | IN | 0 ETH | 0.00112753 | ||||
Safe Redeem ETH | 17835400 | 355 days ago | IN | 0 ETH | 0.00301752 | ||||
Safe Redeem ETH | 17834211 | 355 days ago | IN | 0 ETH | 0.0013992 | ||||
Safe Deposit ETH | 17834197 | 355 days ago | IN | 0.1 ETH | 0.00185993 | ||||
Safe Deposit ETH | 17705298 | 373 days ago | IN | 0.190704 ETH | 0.00206086 | ||||
Safe Deposit ETH | 17647382 | 381 days ago | IN | 8.5 ETH | 0.00161173 | ||||
0x60c06040 | 17619095 | 385 days ago | IN | Create: WethZap | 0 ETH | 0.01943583 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
19828975 | 76 days ago | 0.010489 ETH | ||||
19794743 | 80 days ago | 0.033767 ETH | ||||
19527407 | 118 days ago | 21.44 ETH | ||||
19472994 | 126 days ago | 0.094 ETH | ||||
19391064 | 137 days ago | 0.01 ETH | ||||
18748814 | 227 days ago | 0.15187187 ETH | ||||
18748814 | 227 days ago | 0.15187187 ETH | ||||
18539223 | 256 days ago | 8.5078538 ETH | ||||
18539223 | 256 days ago | 8.5078538 ETH | ||||
18399901 | 276 days ago | 0.604496 ETH | ||||
18399901 | 276 days ago | 0.604496 ETH | ||||
18399450 | 276 days ago | 0.01 ETH | ||||
18399450 | 276 days ago | 0.01 ETH | ||||
18399428 | 276 days ago | 0.01 ETH | ||||
18399420 | 276 days ago | 0.009999 ETH | ||||
18399420 | 276 days ago | 0.009999 ETH | ||||
18399413 | 276 days ago | 0.01 ETH | ||||
18397345 | 276 days ago | 0.00999999 ETH | ||||
18397345 | 276 days ago | 0.00999999 ETH | ||||
18397255 | 276 days ago | 0.01 ETH | ||||
18199619 | 304 days ago | 159.53181919 ETH | ||||
18199619 | 304 days ago | 159.53181919 ETH | ||||
18117085 | 316 days ago | 20.14989021 ETH | ||||
18117085 | 316 days ago | 20.14989021 ETH | ||||
17835400 | 355 days ago | 6.03625505 ETH |
Loading...
Loading
Contract Name:
WethZap
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "solmate/tokens/WETH.sol"; import "solmate/utils/SafeTransferLib.sol"; import "../libraries/Ownable.sol"; import "../Vault.sol"; /// @notice contract to deposit/withdraw native tokens, e.g. ETH/WETH, MATIC/WMATIC contract WethZap is Ownable { using SafeTransferLib for WETH; Vault public immutable vault; WETH public immutable WETH9; bool public paused; event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); event Withdraw(address indexed owner, uint256 assets, uint256 shares); error NoDepositETH(); error Paused(); error AlreadyValue(); modifier whenNotPaused() { if (paused) revert Paused(); _; } constructor(Vault _vault) { vault = _vault; WETH9 = WETH(payable(address(_vault.asset()))); } receive() external payable { if (msg.sender != address(WETH9)) revert NoDepositETH(); // use the depositETH function } function pause() external onlyOwner { if (paused) revert AlreadyValue(); paused = true; } function unpause() external onlyOwner { if (!paused) revert AlreadyValue(); paused = false; } function safeDepositETH(address _receiver, uint256 _minShares) external payable whenNotPaused returns (uint256 shares) { WETH9.deposit{value: msg.value}(); WETH9.safeApprove(address(vault), msg.value); shares = vault.safeDeposit(msg.value, _receiver, _minShares); emit Deposit(msg.sender, _receiver, msg.value, shares); } function depositETH(address _receiver) external payable whenNotPaused returns (uint256 shares) { WETH9.deposit{value: msg.value}(); WETH9.safeApprove(address(vault), msg.value); shares = vault.deposit(msg.value, _receiver); emit Deposit(msg.sender, _receiver, msg.value, shares); } /// @notice user has to approve zap using vault share tokens function safeRedeemETH(uint256 _shares, uint256 _minAssets) external whenNotPaused returns (uint256 assets) { assets = vault.safeRedeem(_shares, address(this), msg.sender, _minAssets); WETH9.withdraw(assets); SafeTransferLib.safeTransferETH(msg.sender, assets); emit Withdraw(msg.sender, assets, _shares); } /// @notice user has to approve zap using vault share tokens function redeemETH(uint256 _shares) external whenNotPaused returns (uint256 assets) { assets = vault.redeem(_shares, address(this), msg.sender); WETH9.withdraw(assets); SafeTransferLib.safeTransferETH(msg.sender, assets); emit Withdraw(msg.sender, assets, _shares); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "./ERC20.sol"; import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; /// @notice Minimalist and modern Wrapped Ether implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/WETH.sol) /// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol) contract WETH is ERC20("Wrapped Ether", "WETH", 18) { using SafeTransferLib for address; event Deposit(address indexed from, uint256 amount); event Withdrawal(address indexed to, uint256 amount); function deposit() public payable virtual { _mint(msg.sender, msg.value); emit Deposit(msg.sender, msg.value); } function withdraw(uint256 amount) public virtual { _burn(msg.sender, amount); emit Withdrawal(msg.sender, amount); msg.sender.safeTransferETH(amount); } receive() external payable virtual { deposit(); } }
// 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/transmissions11/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; /// @solidity memory-safe-assembly 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; /// @solidity memory-safe-assembly 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; /// @solidity memory-safe-assembly 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; /// @solidity memory-safe-assembly 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: MIT pragma solidity 0.8.9; abstract contract Ownable { address public owner; address public nominatedOwner; error Unauthorized(); event OwnerChanged(address indexed previousOwner, address indexed newOwner); constructor() { owner = msg.sender; } // Public Functions function acceptOwnership() external { if (msg.sender != nominatedOwner) revert Unauthorized(); emit OwnerChanged(owner, msg.sender); owner = msg.sender; nominatedOwner = address(0); } // Restricted Functions: onlyOwner /// @dev nominating zero address revokes a pending nomination function nominateOwnership(address _newOwner) external onlyOwner { nominatedOwner = _newOwner; } // Modifiers modifier onlyOwner() { if (msg.sender != owner) revert Unauthorized(); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "solmate/tokens/ERC20.sol"; import "solmate/utils/SafeTransferLib.sol"; import "solmate/utils/FixedPointMathLib.sol"; import "./libraries/Ownership.sol"; import "./libraries/BlockDelay.sol"; import "./interfaces/IERC4626.sol"; import "./Strategy.sol"; contract Vault is ERC20, IERC4626, Ownership, BlockDelay { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /// @notice token which the vault uses and accumulates ERC20 public immutable asset; /// @notice whether deposits and withdrawals are paused bool public paused; uint256 private _lockedProfit; /// @notice timestamp of last report, used for locked profit calculations uint256 public lastReport; /// @notice period over which profits are gradually unlocked, defense against sandwich attacks uint256 public lockedProfitDuration = 24 hours; uint256 internal constant MAX_LOCKED_PROFIT_DURATION = 3 days; /// @dev maximum user can deposit in a single tx uint256 private _maxDeposit = type(uint256).max; struct StrategyParams { bool added; uint256 debt; uint256 debtRatio; } Strategy[] private _queue; mapping(Strategy => StrategyParams) public strategies; uint8 internal constant MAX_QUEUE_LENGTH = 20; uint256 public totalDebt; /// @dev proportion of funds kept in vault to facilitate user withdrawals uint256 public floatDebtRatio; uint256 public totalDebtRatio; uint256 internal constant MAX_TOTAL_DEBT_RATIO = 1_000; /*////////////////// / Events / //////////////////*/ event Report(Strategy indexed strategy, uint256 harvested, uint256 gain, uint256 loss); event Lend(Strategy indexed strategy, uint256 assets, uint256 slippage); event Collect(Strategy indexed strategy, uint256 received, uint256 slippage, uint256 bonus); event StrategyAdded(Strategy indexed strategy, uint256 debtRatio); event StrategyDebtRatioChanged(Strategy indexed strategy, uint256 newDebtRatio); event StrategyRemoved(Strategy indexed strategy); event StrategyQueuePositionsSwapped(uint8 i, uint8 j, Strategy indexed newI, Strategy indexed newJ); event LockedProfitDurationChanged(uint256 newDuration); event MaxDepositChanged(uint256 newMaxDeposit); event FloatDebtRatioChanged(uint256 newFloatDebtRatio); /*////////////////// / Errors / //////////////////*/ error Zero(); error BelowMinimum(uint256); error AboveMaximum(uint256); error AboveMaxDeposit(); error AlreadyStrategy(); error NotStrategy(); error StrategyDoesNotBelongToQueue(); error StrategyQueueFull(); error AlreadyValue(); error Paused(); /// @dev e.g. USDC becomes 'Unagii USD Coin Vault v3' and 'uUSDCv3' constructor( ERC20 _asset, uint8 _blockDelay, uint256 _floatDebtRatio, address _nominatedOwner, address _admin, address[] memory _authorized ) ERC20( string(abi.encodePacked("Unagii ", _asset.name(), " Vault v3")), string(abi.encodePacked("u", _asset.symbol(), "v3")), _asset.decimals() ) Ownership(_nominatedOwner, _admin, _authorized) BlockDelay(_blockDelay) { asset = _asset; _setFloatDebtRatio(_floatDebtRatio); } /*/////////////////////// / Public View / ///////////////////////*/ function queue() external view returns (Strategy[] memory) { return _queue; } function totalAssets() public view returns (uint256 assets) { return asset.balanceOf(address(this)) + totalDebt; } function lockedProfit() public view returns (uint256 lockedAssets) { uint256 last = lastReport; uint256 duration = lockedProfitDuration; unchecked { // won't overflow since time is nowhere near uint256.max if (block.timestamp >= last + duration) return 0; // can overflow if _lockedProfit * difference > uint256.max but in practice should never happen return _lockedProfit - _lockedProfit.mulDivDown(block.timestamp - last, duration); } } function freeAssets() public view returns (uint256 assets) { return totalAssets() - lockedProfit(); } function convertToShares(uint256 _assets) public view returns (uint256 shares) { uint256 supply = totalSupply; return supply == 0 ? _assets : _assets.mulDivDown(supply, totalAssets()); } function convertToAssets(uint256 _shares) public view returns (uint256 assets) { uint256 supply = totalSupply; return supply == 0 ? _shares : _shares.mulDivDown(totalAssets(), supply); } function maxDeposit(address) external view returns (uint256 assets) { return _maxDeposit; } function previewDeposit(uint256 _assets) public view returns (uint256 shares) { return convertToShares(_assets); } function maxMint(address) external view returns (uint256 shares) { return convertToShares(_maxDeposit); } function previewMint(uint256 shares) public view returns (uint256 assets) { uint256 supply = totalSupply; return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); } function maxWithdraw(address owner) external view returns (uint256 assets) { return convertToAssets(balanceOf[owner]); } function previewWithdraw(uint256 assets) public view returns (uint256 shares) { uint256 supply = totalSupply; return supply == 0 ? assets : assets.mulDivUp(supply, freeAssets()); } function maxRedeem(address _owner) external view returns (uint256 shares) { return balanceOf[_owner]; } function previewRedeem(uint256 shares) public view returns (uint256 assets) { uint256 supply = totalSupply; return supply == 0 ? shares : shares.mulDivDown(freeAssets(), supply); } /*//////////////////////////// / Public Functions / ////////////////////////////*/ function safeDeposit(uint256 _assets, address _receiver, uint256 _minShares) external returns (uint256 shares) { shares = deposit(_assets, _receiver); if (shares < _minShares) revert BelowMinimum(shares); } function safeMint(uint256 _shares, address _receiver, uint256 _maxAssets) external returns (uint256 assets) { assets = mint(_shares, _receiver); if (assets > _maxAssets) revert AboveMaximum(assets); } function safeWithdraw(uint256 _assets, address _receiver, address _owner, uint256 _maxShares) external returns (uint256 shares) { shares = withdraw(_assets, _receiver, _owner); if (shares > _maxShares) revert AboveMaximum(shares); } function safeRedeem(uint256 _shares, address _receiver, address _owner, uint256 _minAssets) external returns (uint256 assets) { assets = redeem(_shares, _receiver, _owner); if (assets < _minAssets) revert BelowMinimum(assets); } /*//////////////////////////////////// / ERC4626 Public Functions / ////////////////////////////////////*/ function deposit(uint256 _assets, address _receiver) public whenNotPaused returns (uint256 shares) { if ((shares = previewDeposit(_assets)) == 0) revert Zero(); _deposit(_assets, shares, _receiver); } function mint(uint256 _shares, address _receiver) public whenNotPaused returns (uint256 assets) { if (_shares == 0) revert Zero(); assets = previewMint(_shares); _deposit(assets, _shares, _receiver); } function withdraw(uint256 _assets, address _receiver, address _owner) public returns (uint256 shares) { if (_assets == 0) revert Zero(); shares = previewWithdraw(_assets); _withdraw(_assets, shares, _owner, _receiver); } function redeem(uint256 _shares, address _receiver, address _owner) public returns (uint256 assets) { if ((assets = previewRedeem(_shares)) == 0) revert Zero(); return _withdraw(assets, _shares, _owner, _receiver); } /*/////////////////////////////////////////// / Restricted Functions: onlyOwner / ///////////////////////////////////////////*/ function addStrategy(Strategy _strategy, uint256 _debtRatio) external onlyOwner { if (_strategy.vault() != this) revert StrategyDoesNotBelongToQueue(); if (strategies[_strategy].added) revert AlreadyStrategy(); if (_queue.length >= MAX_QUEUE_LENGTH) revert StrategyQueueFull(); totalDebtRatio += _debtRatio; if (totalDebtRatio > MAX_TOTAL_DEBT_RATIO) revert AboveMaximum(totalDebtRatio); strategies[_strategy] = StrategyParams({added: true, debt: 0, debtRatio: _debtRatio}); _queue.push(_strategy); emit StrategyAdded(_strategy, _debtRatio); } /*//////////////////////////////////////////// / Restricted Functions: onlyAdmins / ////////////////////////////////////////////*/ function removeStrategy(Strategy _strategy, bool _shouldHarvest, uint256 _minReceived) external onlyAdmins returns (uint256 received) { if (!strategies[_strategy].added) revert NotStrategy(); _setDebtRatio(_strategy, 0); uint256 balanceBefore = asset.balanceOf(address(this)); if (_shouldHarvest) _harvest(_strategy); else _report(_strategy, 0); received = asset.balanceOf(address(this)) - balanceBefore; if (received < _minReceived) revert BelowMinimum(received); // reorganize queue, filling in the empty strategy Strategy[] memory newQueue = new Strategy[](_queue.length - 1); bool found; uint8 length = uint8(newQueue.length); for (uint8 i = 0; i < length; ++i) { if (_queue[i] == _strategy) found = true; if (found) newQueue[i] = _queue[i + 1]; else newQueue[i] = _queue[i]; } delete strategies[_strategy]; _queue = newQueue; emit StrategyRemoved(_strategy); } function swapQueuePositions(uint8 _i, uint8 _j) external onlyAdmins { Strategy s1 = _queue[_i]; Strategy s2 = _queue[_j]; _queue[_i] = s2; _queue[_j] = s1; emit StrategyQueuePositionsSwapped(_i, _j, s2, s1); } function setDebtRatio(Strategy _strategy, uint256 _newDebtRatio) external onlyAdmins { if (!strategies[_strategy].added) revert NotStrategy(); _setDebtRatio(_strategy, _newDebtRatio); } /// @dev locked profit duration can be 0 function setLockedProfitDuration(uint256 _newDuration) external onlyAdmins { if (_newDuration > MAX_LOCKED_PROFIT_DURATION) revert AboveMaximum(_newDuration); if (_newDuration == lockedProfitDuration) revert AlreadyValue(); lockedProfitDuration = _newDuration; emit LockedProfitDurationChanged(_newDuration); } function setBlockDelay(uint8 _newDelay) external onlyAdmins { _setBlockDelay(_newDelay); } /*/////////////////////////////////////////////// / Restricted Functions: onlyAuthorized / ///////////////////////////////////////////////*/ function suspendStrategy(Strategy _strategy) external onlyAuthorized { if (!strategies[_strategy].added) revert NotStrategy(); _setDebtRatio(_strategy, 0); } function collectFromStrategy(Strategy _strategy, uint256 _assets, uint256 _minReceived) external onlyAuthorized returns (uint256 received) { if (!strategies[_strategy].added) revert NotStrategy(); (received,) = _collect(_strategy, _assets, address(this)); if (received < _minReceived) revert BelowMinimum(received); } function pause() external onlyAuthorized { if (paused) revert AlreadyValue(); paused = true; } function unpause() external onlyAuthorized { if (!paused) revert AlreadyValue(); paused = false; } function setMaxDeposit(uint256 _newMaxDeposit) external onlyAuthorized { if (_maxDeposit == _newMaxDeposit) revert AlreadyValue(); _maxDeposit = _newMaxDeposit; emit MaxDepositChanged(_newMaxDeposit); } /// @dev costs less gas than multiple harvests if active strategies > 1 function harvestAll() external onlyAuthorized updateLastReport { uint8 length = uint8(_queue.length); for (uint8 i = 0; i < length; ++i) { _harvest(_queue[i]); } } /// @dev costs less gas than multiple reports if active strategies > 1 function reportAll() external onlyAuthorized updateLastReport { uint8 length = uint8(_queue.length); for (uint8 i = 0; i < length; ++i) { _report(_queue[i], 0); } } function harvest(Strategy _strategy) external onlyAuthorized updateLastReport { if (!strategies[_strategy].added) revert NotStrategy(); _harvest(_strategy); } function report(Strategy _strategy) external onlyAuthorized updateLastReport { if (!strategies[_strategy].added) revert NotStrategy(); _report(_strategy, 0); } function setFloatDebtRatio(uint256 _floatDebtRatio) external onlyAuthorized { _setFloatDebtRatio(_floatDebtRatio); } /*/////////////////////////////////////////// / Internal Override: useBlockDelay / ///////////////////////////////////////////*/ /// @dev address cannot mint/burn/send/receive share tokens on same block, defense against flash loan exploits function _mint(address _to, uint256 _amount) internal override useBlockDelay(_to) { if (_to == address(0)) revert Zero(); ERC20._mint(_to, _amount); } /// @dev address cannot mint/burn/send/receive share tokens on same block, defense against flash loan exploits function _burn(address _from, uint256 _amount) internal override useBlockDelay(_from) { ERC20._burn(_from, _amount); } /// @dev address cannot mint/burn/send/receive share tokens on same block, defense against flash loan exploits function transfer(address _to, uint256 _amount) public override useBlockDelay(msg.sender) useBlockDelay(_to) returns (bool) { return ERC20.transfer(_to, _amount); } /// @dev address cannot mint/burn/send/receive share tokens on same block, defense against flash loan exploits function transferFrom(address _from, address _to, uint256 _amount) public override useBlockDelay(_from) useBlockDelay(_to) returns (bool) { return ERC20.transferFrom(_from, _to, _amount); } /*////////////////////////////// / Internal Functions / //////////////////////////////*/ function _deposit(uint256 _assets, uint256 _shares, address _receiver) internal { if (_assets > _maxDeposit) revert AboveMaxDeposit(); asset.safeTransferFrom(msg.sender, address(this), _assets); _mint(_receiver, _shares); emit Deposit(msg.sender, _receiver, _assets, _shares); } function _withdraw(uint256 _assets, uint256 _shares, address _owner, address _receiver) internal returns (uint256 received) { if (msg.sender != _owner) { uint256 allowed = allowance[_owner][msg.sender]; if (allowed != type(uint256).max) allowance[_owner][msg.sender] = allowed - _shares; } _burn(_owner, _shares); emit Withdraw(msg.sender, _receiver, _owner, _assets, _shares); // first, withdraw from balance uint256 balance = asset.balanceOf(address(this)); if (balance > 0) { uint256 amount = _assets > balance ? balance : _assets; asset.safeTransfer(_receiver, amount); _assets -= amount; received += amount; } // next, withdraw from strategies uint8 length = uint8(_queue.length); for (uint8 i = 0; i < length; ++i) { if (_assets == 0) break; (uint256 receivedFromStrategy, uint256 slippage) = _collect(_queue[i], _assets, _receiver); _assets -= receivedFromStrategy + slippage; // user pays for slippage, if any received += receivedFromStrategy; } } /// @dev do not touch debt outside of _lend(), _collect() and _report() function _lend(Strategy _strategy, uint256 _assets) internal { uint256 balance = asset.balanceOf(address(this)); uint256 amount = _assets > balance ? balance : _assets; asset.safeTransfer(address(_strategy), amount); _strategy.invest(); uint256 debtBefore = strategies[_strategy].debt; uint256 debtAfter = _strategy.totalAssets(); uint256 diff = debtAfter - debtBefore; uint256 slippage = amount > diff ? amount - diff : 0; // ignore bonus if diff > amount, safeguard against imprecise `strategy.totalAsset()` calculations that open vault to being drained uint256 debt = amount - slippage; strategies[_strategy].debt += debt; totalDebt += debt; emit Lend(_strategy, amount, slippage); } function _collect(Strategy _strategy, uint256 _assets, address _receiver) internal returns (uint256 received, uint256 slippage) { uint256 bonus; (received, slippage, bonus) = _strategy.withdraw(_assets); uint256 total = received + slippage; uint256 debt = strategies[_strategy].debt; uint256 amount = debt > total ? received : total; strategies[_strategy].debt -= amount; totalDebt -= amount; // do not pass bonuses on to users withdrawing, prevents exploits draining vault if (_receiver == address(this)) emit Collect(_strategy, received, slippage, bonus); else asset.safeTransfer(_receiver, received); } function _harvest(Strategy _strategy) internal { _report(_strategy, _strategy.harvest()); } /// @dev do not touch debt outside of _lend(), _collect() and _report() function _report(Strategy _strategy, uint256 _harvested) internal { uint256 assets = _strategy.totalAssets(); uint256 debt = strategies[_strategy].debt; strategies[_strategy].debt = assets; // update debt uint256 gain; uint256 loss; uint256 lockedProfitBefore = lockedProfit(); if (assets > debt) { unchecked { gain = assets - debt; } totalDebt += gain; _lockedProfit = lockedProfitBefore + gain + _harvested; } else if (debt > assets) { unchecked { loss = debt - assets; totalDebt -= loss; _lockedProfit = lockedProfitBefore + _harvested > loss ? lockedProfitBefore + _harvested - loss : 0; } } uint256 possibleDebt = totalDebtRatio == 0 ? 0 : totalAssets().mulDivDown(strategies[_strategy].debtRatio, totalDebtRatio); if (possibleDebt > assets) _lend(_strategy, possibleDebt - assets); else if (assets > possibleDebt) _collect(_strategy, assets - possibleDebt, address(this)); emit Report(_strategy, _harvested, gain, loss); } function _setDebtRatio(Strategy _strategy, uint256 _newDebtRatio) internal { uint256 currentDebtRatio = strategies[_strategy].debtRatio; if (_newDebtRatio == currentDebtRatio) revert AlreadyValue(); uint256 newTotalDebtRatio = totalDebtRatio + _newDebtRatio - currentDebtRatio; if (newTotalDebtRatio > MAX_TOTAL_DEBT_RATIO) revert AboveMaximum(newTotalDebtRatio); strategies[_strategy].debtRatio = _newDebtRatio; totalDebtRatio = newTotalDebtRatio; emit StrategyDebtRatioChanged(_strategy, _newDebtRatio); } function _setFloatDebtRatio(uint256 _floatDebtRatio) internal { uint256 newTotalDebtRatio = totalDebtRatio + _floatDebtRatio - floatDebtRatio; if (newTotalDebtRatio > MAX_TOTAL_DEBT_RATIO) revert AboveMaximum(newTotalDebtRatio); floatDebtRatio = _floatDebtRatio; totalDebtRatio = newTotalDebtRatio; emit FloatDebtRatioChanged(_floatDebtRatio); } /*///////////////////// / Modifiers / /////////////////////*/ modifier updateLastReport() { _; lastReport = block.timestamp; } modifier whenNotPaused() { if (paused) revert Paused(); _; } }
// 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/transmissions11/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 Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/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 MAX_UINT256 = 2**256 - 1; 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) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly 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) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. 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))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; abstract contract Ownership { address public owner; address public nominatedOwner; address public admin; mapping(address => bool) public authorized; event OwnerChanged(address indexed previousOwner, address indexed newOwner); event AuthAdded(address indexed newAuth); event AuthRemoved(address indexed oldAuth); error Unauthorized(); error AlreadyRole(); error NotRole(); /// @param _authorized maximum of 256 addresses in constructor constructor(address _nominatedOwner, address _admin, address[] memory _authorized) { owner = msg.sender; nominatedOwner = _nominatedOwner; admin = _admin; for (uint8 i = 0; i < _authorized.length; ++i) { authorized[_authorized[i]] = true; emit AuthAdded(_authorized[i]); } } // Public Functions function acceptOwnership() external { if (msg.sender != nominatedOwner) revert Unauthorized(); emit OwnerChanged(owner, msg.sender); owner = msg.sender; nominatedOwner = address(0); } // Restricted Functions: onlyOwner /// @dev nominating zero address revokes a pending nomination function nominateOwnership(address _newOwner) external onlyOwner { nominatedOwner = _newOwner; } function setAdmin(address _newAdmin) external onlyOwner { if (admin == _newAdmin) revert AlreadyRole(); admin = _newAdmin; } // Restricted Functions: onlyAdmins function addAuthorized(address _authorized) external onlyAdmins { if (authorized[_authorized]) revert AlreadyRole(); authorized[_authorized] = true; emit AuthAdded(_authorized); } function removeAuthorized(address _authorized) external onlyAdmins { if (!authorized[_authorized]) revert NotRole(); authorized[_authorized] = false; emit AuthRemoved(_authorized); } // Modifiers modifier onlyOwner() { if (msg.sender != owner) revert Unauthorized(); _; } modifier onlyAdmins() { if (msg.sender != owner && msg.sender != admin) revert Unauthorized(); _; } modifier onlyAuthorized() { if (msg.sender != owner && msg.sender != admin && !authorized[msg.sender]) revert Unauthorized(); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; abstract contract BlockDelay { /// @notice delay before functions with 'useBlockDelay' can be called by the same address /// @dev 0 means no delay uint256 public blockDelay; uint256 internal constant MAX_BLOCK_DELAY = 10; mapping(address => uint256) public lastBlock; error AboveMaxBlockDelay(); error BeforeBlockDelay(); constructor(uint8 _delay) { _setBlockDelay(_delay); } function _setBlockDelay(uint8 _newDelay) internal { if (_newDelay > MAX_BLOCK_DELAY) revert AboveMaxBlockDelay(); blockDelay = _newDelay; } modifier useBlockDelay(address _address) { if (block.number < lastBlock[_address] + blockDelay) revert BeforeBlockDelay(); lastBlock[_address] = block.number; _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import "solmate/tokens/ERC20.sol"; /// @notice https://eips.ethereum.org/EIPS/eip-4626 interface IERC4626 { 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 ); function asset() external view returns (ERC20); function totalAssets() external view returns (uint256 assets); function convertToShares(uint256 assets) external view returns (uint256 shares); function convertToAssets(uint256 shares) external view returns (uint256 assets); function maxDeposit(address receiver) external view returns (uint256 assets); function previewDeposit(uint256 assets) external view returns (uint256 shares); function deposit(uint256 assets, address receiver) external returns (uint256 shares); function maxMint(address receiver) external view returns (uint256 shares); function previewMint(uint256 shares) external view returns (uint256 assets); function mint(uint256 shares, address receiver) external returns (uint256 assets); function maxWithdraw(address owner) external view returns (uint256 assets); function previewWithdraw(uint256 assets) external view returns (uint256 shares); function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); function maxRedeem(address owner) external view returns (uint256 shares); function previewRedeem(uint256 shares) external view returns (uint256 assets); function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.9; import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol"; import {ERC20} from "solmate/tokens/ERC20.sol"; import {Ownership} from "./libraries/Ownership.sol"; import "./Vault.sol"; /** * @dev * Strategies have to implement the following virtual functions: * * totalAssets() * _withdraw(uint256, address) * _harvest() * _invest() */ abstract contract Strategy is Ownership { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; Vault public immutable vault; ERC20 public immutable asset; /// @notice address which performance fees are sent to address public treasury; /// @notice performance fee sent to treasury / FEE_BASIS of 10_000 uint16 public fee = 1_000; uint16 internal constant MAX_FEE = 1_000; uint16 internal constant FEE_BASIS = 10_000; /// @notice used to calculate slippage / SLIP_BASIS of 10_000 /// @dev default to 99% (or 1%) uint16 public slip = 9_900; uint16 internal constant SLIP_BASIS = 10_000; /*////////////////// / Events / //////////////////*/ event FeeChanged(uint16 newFee); event SlipChanged(uint16 newSlip); event TreasuryChanged(address indexed newTreasury); /*////////////////// / Errors / //////////////////*/ error Zero(); error NotVault(); error InvalidValue(); error AlreadyValue(); constructor(Vault _vault, address _treasury, address _nominatedOwner, address _admin, address[] memory _authorized) Ownership(_nominatedOwner, _admin, _authorized) { vault = _vault; asset = vault.asset(); treasury = _treasury; } /*////////////////////////// / Public Virtual / //////////////////////////*/ /// @notice amount of 'asset' currently managed by strategy function totalAssets() public view virtual returns (uint256); /*/////////////////////////////////////////// / Restricted Functions: onlyVault / ///////////////////////////////////////////*/ function withdraw(uint256 _assets) external onlyVault returns (uint256 received, uint256 slippage, uint256 bonus) { uint256 total = totalAssets(); if (total == 0) revert Zero(); uint256 assets = _assets > total ? total : _assets; received = _withdraw(assets); unchecked { if (assets > received) { slippage = assets - received; } else if (received > assets) { bonus = received - assets; // received cannot > assets for vault calcuations received = assets; } } } /*////////////////////////////////////////////////// / Restricted Functions: onlyAdminOrVault / //////////////////////////////////////////////////*/ function harvest() external onlyAdminOrVault returns (uint256 received) { _harvest(); received = asset.balanceOf(address(this)); if (fee > 0) { uint256 feeAmount = _calculateFee(received); received -= feeAmount; asset.safeTransfer(treasury, feeAmount); } asset.safeTransfer(address(vault), received); } function invest() external onlyAdminOrVault { _invest(); } /*/////////////////////////////////////////// / Restricted Functions: onlyOwner / ///////////////////////////////////////////*/ function setFee(uint16 _fee) external onlyOwner { if (_fee > MAX_FEE) revert InvalidValue(); if (_fee == fee) revert AlreadyValue(); fee = _fee; emit FeeChanged(_fee); } function setTreasury(address _treasury) external onlyOwner { if (_treasury == treasury) revert AlreadyValue(); treasury = _treasury; emit TreasuryChanged(_treasury); } /*//////////////////////////////////////////// / Restricted Functions: onlyAdmins / ////////////////////////////////////////////*/ function setSlip(uint16 _slip) external onlyAdmins { if (_slip > SLIP_BASIS) revert InvalidValue(); if (_slip == slip) revert AlreadyValue(); slip = _slip; emit SlipChanged(_slip); } /*//////////////////////////// / Internal Virtual / ////////////////////////////*/ function _withdraw(uint256 _assets) internal virtual returns (uint256 received); /// @dev return harvested assets function _harvest() internal virtual; function _invest() internal virtual; /*////////////////////////////// / Internal Functions / //////////////////////////////*/ function _calculateSlippage(uint256 _amount) internal view returns (uint256) { return _amount.mulDivDown(slip, SLIP_BASIS); } function _calculateFee(uint256 _amount) internal view returns (uint256) { return _amount.mulDivDown(fee, FEE_BASIS); } modifier onlyVault() { if (msg.sender != address(vault)) revert NotVault(); _; } /*////////////////////////////// / Internal Functions / //////////////////////////////*/ modifier onlyAdminOrVault() { if (msg.sender != owner && msg.sender != admin && msg.sender != address(vault)) revert Unauthorized(); _; } }
{ "remappings": [ "ds-test/=lib/solmate/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 10000 }, "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
[{"inputs":[{"internalType":"contract Vault","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyValue","type":"error"},{"inputs":[],"name":"NoDepositETH","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"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":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"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":"WETH9","outputs":[{"internalType":"contract WETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"}],"name":"depositETH","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"nominateOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"redeemETH","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_minShares","type":"uint256"}],"name":"safeDepositETH","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"uint256","name":"_minAssets","type":"uint256"}],"name":"safeRedeemETH","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract Vault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c060405234801561001057600080fd5b5060405161132638038061132683398101604081905261002f916100e8565b600080546001600160a01b031916331790556001600160a01b0381166080819052604080516338d52e0f60e01b815290516338d52e0f91600480820192602092909190829003018186803b15801561008657600080fd5b505afa15801561009a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100be91906100e8565b6001600160a01b031660a0525061010c565b6001600160a01b03811681146100e557600080fd5b50565b6000602082840312156100fa57600080fd5b8151610105816100d0565b9392505050565b60805160a05161119b61018b6000396000818160f3015281816101b1015281816103ac0152818161044401528181610613015281816106ab01528181610a3d0152610e0a01526000818161033001528181610468015281816104e1015281816106cf015281816107410152818161097a0152610d47015261119b6000f3fe6080604052600436106100d65760003560e01c80635c975abb1161007f57806388908b261161005957806388908b26146102b15780638da5cb5b146102d1578063d9380519146102fe578063fbfa77cf1461031e57600080fd5b80635c975abb1461024557806379ba5097146102875780638456cb591461029c57600080fd5b80634aa4a4fc116100b05780634aa4a4fc1461019f578063525d02b8146101f857806353a47bb71461021857600080fd5b806327ce1619146101515780632d2da806146101775780633f4ba83a1461018a57600080fd5b3661014c573373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461014a576040517fbfb1c5f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b61016461015f3660046110c5565b610352565b6040519081526020015b60405180910390f35b6101646101853660046110ef565b6105b9565b34801561019657600080fd5b5061014a610818565b3480156101ab57600080fd5b506101d37f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b34801561020457600080fd5b50610164610213366004611111565b6108e7565b34801561022457600080fd5b506001546101d39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561025157600080fd5b506001546102779074010000000000000000000000000000000000000000900460ff1681565b604051901515815260200161016e565b34801561029357600080fd5b5061014a610af8565b3480156102a857600080fd5b5061014a610bc6565b3480156102bd57600080fd5b506101646102cc36600461112a565b610cad565b3480156102dd57600080fd5b506000546101d39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561030a57600080fd5b5061014a6103193660046110ef565b610ec6565b34801561032a57600080fd5b506101d37f000000000000000000000000000000000000000000000000000000000000000081565b60015460009074010000000000000000000000000000000000000000900460ff16156103aa576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561041257600080fd5b505af1158015610426573d6000803e3d6000fd5b5061048f93505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691507f0000000000000000000000000000000000000000000000000000000000000000905034610f5e565b6040517fc12a8e5c00000000000000000000000000000000000000000000000000000000815234600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018490527f0000000000000000000000000000000000000000000000000000000000000000169063c12a8e5c90606401602060405180830381600087803b15801561052557600080fd5b505af1158015610539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055d919061114c565b604080513481526020810183905291925073ffffffffffffffffffffffffffffffffffffffff85169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b60015460009074010000000000000000000000000000000000000000900460ff1615610611576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561067957600080fd5b505af115801561068d573d6000803e3d6000fd5b506106f693505073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691507f0000000000000000000000000000000000000000000000000000000000000000905034610f5e565b6040517f6e553f6500000000000000000000000000000000000000000000000000000000815234600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301527f00000000000000000000000000000000000000000000000000000000000000001690636e553f6590604401602060405180830381600087803b15801561078557600080fd5b505af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd919061114c565b604080513481526020810183905291925073ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3919050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610869576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015474010000000000000000000000000000000000000000900460ff166108bd576040517fc4d933da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60015460009074010000000000000000000000000000000000000000900460ff161561093f576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fba087652000000000000000000000000000000000000000000000000000000008152600481018390523060248201523360448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063ba08765290606401602060405180830381600087803b1580156109d357600080fd5b505af11580156109e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0b919061114c565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015610a9657600080fd5b505af1158015610aaa573d6000803e3d6000fd5b50505050610ab83382611022565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b49576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054604051339273ffffffffffffffffffffffffffffffffffffffff909216917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081163317909155600180549091169055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c17576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015474010000000000000000000000000000000000000000900460ff1615610c6c576040517fc4d933da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009074010000000000000000000000000000000000000000900460ff1615610d05576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9f30380a00000000000000000000000000000000000000000000000000000000815260048101849052306024820152336044820152606481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639f30380a90608401602060405180830381600087803b158015610da057600080fd5b505af1158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd8919061114c565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015610e6357600080fd5b505af1158015610e77573d6000803e3d6000fd5b50505050610e853382611022565b604080518281526020810185905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a292915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f17576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061101c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c454400000000000000000000000000000000000060448201526064015b60405180910390fd5b50505050565b600080600080600085875af1905080611097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401611013565b505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110c057600080fd5b919050565b600080604083850312156110d857600080fd5b6110e18361109c565b946020939093013593505050565b60006020828403121561110157600080fd5b61110a8261109c565b9392505050565b60006020828403121561112357600080fd5b5035919050565b6000806040838503121561113d57600080fd5b50508035926020909101359150565b60006020828403121561115e57600080fd5b505191905056fea2646970667358221220965d1c45489ebb03f2d82044b9d66a3663de326aa9a9b43e979ed4e4491d0ec964736f6c634300080900330000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d
Deployed Bytecode
0x6080604052600436106100d65760003560e01c80635c975abb1161007f57806388908b261161005957806388908b26146102b15780638da5cb5b146102d1578063d9380519146102fe578063fbfa77cf1461031e57600080fd5b80635c975abb1461024557806379ba5097146102875780638456cb591461029c57600080fd5b80634aa4a4fc116100b05780634aa4a4fc1461019f578063525d02b8146101f857806353a47bb71461021857600080fd5b806327ce1619146101515780632d2da806146101775780633f4ba83a1461018a57600080fd5b3661014c573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2161461014a576040517fbfb1c5f200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b005b600080fd5b61016461015f3660046110c5565b610352565b6040519081526020015b60405180910390f35b6101646101853660046110ef565b6105b9565b34801561019657600080fd5b5061014a610818565b3480156101ab57600080fd5b506101d37f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016e565b34801561020457600080fd5b50610164610213366004611111565b6108e7565b34801561022457600080fd5b506001546101d39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561025157600080fd5b506001546102779074010000000000000000000000000000000000000000900460ff1681565b604051901515815260200161016e565b34801561029357600080fd5b5061014a610af8565b3480156102a857600080fd5b5061014a610bc6565b3480156102bd57600080fd5b506101646102cc36600461112a565b610cad565b3480156102dd57600080fd5b506000546101d39073ffffffffffffffffffffffffffffffffffffffff1681565b34801561030a57600080fd5b5061014a6103193660046110ef565b610ec6565b34801561032a57600080fd5b506101d37f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d81565b60015460009074010000000000000000000000000000000000000000900460ff16156103aa576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561041257600080fd5b505af1158015610426573d6000803e3d6000fd5b5061048f93505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691507f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d905034610f5e565b6040517fc12a8e5c00000000000000000000000000000000000000000000000000000000815234600482015273ffffffffffffffffffffffffffffffffffffffff8481166024830152604482018490527f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d169063c12a8e5c90606401602060405180830381600087803b15801561052557600080fd5b505af1158015610539573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055d919061114c565b604080513481526020810183905291925073ffffffffffffffffffffffffffffffffffffffff85169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b60015460009074010000000000000000000000000000000000000000900460ff1615610611576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561067957600080fd5b505af115801561068d573d6000803e3d6000fd5b506106f693505073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21691507f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d905034610f5e565b6040517f6e553f6500000000000000000000000000000000000000000000000000000000815234600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301527f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d1690636e553f6590604401602060405180830381600087803b15801561078557600080fd5b505af1158015610799573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107bd919061114c565b604080513481526020810183905291925073ffffffffffffffffffffffffffffffffffffffff84169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a3919050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610869576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015474010000000000000000000000000000000000000000900460ff166108bd576040517fc4d933da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff169055565b60015460009074010000000000000000000000000000000000000000900460ff161561093f576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fba087652000000000000000000000000000000000000000000000000000000008152600481018390523060248201523360448201527f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d73ffffffffffffffffffffffffffffffffffffffff169063ba08765290606401602060405180830381600087803b1580156109d357600080fd5b505af11580156109e7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0b919061114c565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015610a9657600080fd5b505af1158015610aaa573d6000803e3d6000fd5b50505050610ab83382611022565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b49576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054604051339273ffffffffffffffffffffffffffffffffffffffff909216917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c91a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000009081163317909155600180549091169055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c17576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015474010000000000000000000000000000000000000000900460ff1615610c6c576040517fc4d933da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055565b60015460009074010000000000000000000000000000000000000000900460ff1615610d05576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f9f30380a00000000000000000000000000000000000000000000000000000000815260048101849052306024820152336044820152606481018390527f0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d73ffffffffffffffffffffffffffffffffffffffff1690639f30380a90608401602060405180830381600087803b158015610da057600080fd5b505af1158015610db4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd8919061114c565b6040517f2e1a7d4d000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff1690632e1a7d4d90602401600060405180830381600087803b158015610e6357600080fd5b505af1158015610e77573d6000803e3d6000fd5b50505050610e853382611022565b604080518281526020810185905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a292915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f17576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061101c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c454400000000000000000000000000000000000060448201526064015b60405180910390fd5b50505050565b600080600080600085875af1905080611097576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152606401611013565b505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110c057600080fd5b919050565b600080604083850312156110d857600080fd5b6110e18361109c565b946020939093013593505050565b60006020828403121561110157600080fd5b61110a8261109c565b9392505050565b60006020828403121561112357600080fd5b5035919050565b6000806040838503121561113d57600080fd5b50508035926020909101359150565b60006020828403121561115e57600080fd5b505191905056fea2646970667358221220965d1c45489ebb03f2d82044b9d66a3663de326aa9a9b43e979ed4e4491d0ec964736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d
-----Decoded View---------------
Arg [0] : _vault (address): 0x6aBE5f87E3F4dC87301064F63CA5b244d119980d
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000006abe5f87e3f4dc87301064f63ca5b244d119980d
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.