Overview
GLMR Balance
GLMR Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 950 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Quartz In ETH | 2427265 | 808 days ago | IN | 1 GLMR | 0.08012835 | ||||
Quartz In ETH | 2427252 | 808 days ago | IN | 1 GLMR | 0.13261815 | ||||
Quartz In ETH | 2348758 | 819 days ago | IN | 0.1 GLMR | 0.1233114 | ||||
Quartz In ETH | 2344096 | 820 days ago | IN | 153 GLMR | 0.1305959 | ||||
Quartz In ETH | 2336724 | 821 days ago | IN | 295 GLMR | 0.1061373 | ||||
Quartz Out | 2314597 | 824 days ago | IN | 0 GLMR | 0.0380168 | ||||
Quartz Out | 2314595 | 824 days ago | IN | 0 GLMR | 0.1055344 | ||||
Quartz Out | 2306534 | 825 days ago | IN | 0 GLMR | 0.0660134 | ||||
Quartz In ETH | 2306532 | 825 days ago | IN | 0.11592449 GLMR | 0.1294487 | ||||
Quartz Out | 2296829 | 827 days ago | IN | 0 GLMR | 0.1010627 | ||||
Quartz Out | 2296185 | 827 days ago | IN | 0 GLMR | 0.04834544 | ||||
Quartz In ETH | 2284575 | 828 days ago | IN | 50 GLMR | 0.1283937 | ||||
Quartz In | 2266998 | 831 days ago | IN | 0 GLMR | 0.058944 | ||||
Quartz In ETH | 2266992 | 831 days ago | IN | 18 GLMR | 0.1050362 | ||||
Quartz In | 2266986 | 831 days ago | IN | 0 GLMR | 0.0939872 | ||||
Quartz In | 2266966 | 831 days ago | IN | 0 GLMR | 0.1156935 | ||||
Quartz In | 2241994 | 834 days ago | IN | 0 GLMR | 0.0523224 | ||||
Quartz Out | 2220289 | 837 days ago | IN | 0 GLMR | 0.0644392 | ||||
Quartz In ETH | 2220284 | 837 days ago | IN | 1 GLMR | 0.155858 | ||||
Quartz In | 2216954 | 838 days ago | IN | 0 GLMR | 0.1581356 | ||||
Quartz In ETH | 2214760 | 838 days ago | IN | 166 GLMR | 0.0779767 | ||||
Quartz In ETH | 2202345 | 840 days ago | IN | 11 GLMR | 0.1043957 | ||||
Quartz In | 2202342 | 840 days ago | IN | 0 GLMR | 0.0939856 | ||||
Quartz In | 2202328 | 840 days ago | IN | 0 GLMR | 0.113461 | ||||
Quartz Out | 2194331 | 841 days ago | IN | 0 GLMR | 0.0386189 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
2427265 | 808 days ago | 0.00000112 GLMR | ||||
2427265 | 808 days ago | 0.00000112 GLMR | ||||
2427265 | 808 days ago | 1 GLMR | ||||
2427252 | 808 days ago | 0.00000112 GLMR | ||||
2427252 | 808 days ago | 0.00000112 GLMR | ||||
2427252 | 808 days ago | 1 GLMR | ||||
2348758 | 819 days ago | 0.00000011 GLMR | ||||
2348758 | 819 days ago | 0.00000011 GLMR | ||||
2348758 | 819 days ago | 0.1 GLMR | ||||
2344096 | 820 days ago | 0.00013813 GLMR | ||||
2344096 | 820 days ago | 0.00013813 GLMR | ||||
2344096 | 820 days ago | 153 GLMR | ||||
2336724 | 821 days ago | 0.00012753 GLMR | ||||
2336724 | 821 days ago | 0.00012753 GLMR | ||||
2336724 | 821 days ago | 295 GLMR | ||||
2314597 | 824 days ago | 16.7618159 GLMR | ||||
2314597 | 824 days ago | 16.7618159 GLMR | ||||
2314595 | 824 days ago | 28.56961745 GLMR | ||||
2314595 | 824 days ago | 28.56961745 GLMR | ||||
2306534 | 825 days ago | 25.75266189 GLMR | ||||
2306534 | 825 days ago | 25.75266189 GLMR | ||||
2306532 | 825 days ago | 0.00000013 GLMR | ||||
2306532 | 825 days ago | 0.00000013 GLMR | ||||
2306532 | 825 days ago | 0.11592449 GLMR | ||||
2296829 | 827 days ago | 322.05837521 GLMR |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
QuartzUniV2Zap
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPLv2 // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // @author Wivern for Beefy.Finance, ToweringTopaz for Crystl.Finance // @notice This contract adds liquidity to Uniswap V2 compatible liquidity pair pools and stake. pragma solidity ^0.8.14; import "./libraries/LibQuartz.sol"; contract QuartzUniV2Zap { using SafeERC20 for IERC20; using LibQuartz for IVaultHealer; using VaultChonk for IVaultHealer; uint256 public constant MINIMUM_AMOUNT = 1000; IVaultHealer public immutable vaultHealer; mapping(IERC20 => bool) private approvals; constructor(address _vaultHealer) { vaultHealer = IVaultHealer(_vaultHealer); } receive() external payable { require(Address.isContract(msg.sender)); } function quartzInETH (uint vid, uint256 tokenAmountOutMin) external payable { require(msg.value >= MINIMUM_AMOUNT, 'Quartz: Insignificant input amount'); IWETH weth = vaultHealer.getRouter(vid).WETH(); weth.deposit{value: msg.value}(); _swapAndStake(vid, tokenAmountOutMin, weth); } function estimateSwap(uint vid, IERC20 tokenIn, uint256 fullInvestmentIn) external view returns(uint256 swapAmountIn, uint256 swapAmountOut, IERC20 swapTokenOut) { return LibQuartz.estimateSwap(vaultHealer, vid, tokenIn, fullInvestmentIn); } function quartzIn (uint vid, uint256 tokenAmountOutMin, IERC20 tokenIn, uint256 tokenInAmount) external { uint allowance = tokenIn.allowance(msg.sender, address(this)); uint balance = tokenIn.balanceOf(msg.sender); if (tokenInAmount == type(uint256).max) tokenInAmount = allowance < balance ? allowance : balance; else { require(allowance >= tokenInAmount, 'Quartz: Input token is not approved'); require(balance >= tokenInAmount, 'Quartz: Input token has insufficient balance'); } require(tokenInAmount >= MINIMUM_AMOUNT, 'Quartz: Insignificant input amount'); tokenIn.safeTransferFrom(msg.sender, address(this), tokenInAmount); require(tokenIn.balanceOf(address(this)) >= tokenInAmount, 'Quartz: Fee-on-transfer/reflect tokens not yet supported'); _swapAndStake(vid, tokenAmountOutMin, tokenIn); } //should only happen when this contract deposits as a maximizer function onERC1155Received( address operator, address /*from*/, uint256 /*id*/, uint256 /*amount*/, bytes calldata) external view returns (bytes4) { //if (msg.sender != address(vaultHealer)) revert("Quartz: Incorrect ERC1155 issuer"); if (operator != address(this)) revert("Quartz: Improper ERC1155 transfer"); return 0xf23a6e61; } function quartzOut (uint vid, uint256 withdrawAmount) public { (IUniRouter router,, IUniPair pair, bool isPair) = vaultHealer.getRouterAndPair(vid); if (withdrawAmount > 0) { uint[4] memory data = vaultHealer.tokenData(msg.sender, asSingletonArray(vid))[0]; vaultHealer.safeTransferFrom( msg.sender, address(this), vid, withdrawAmount > data[0] ? //user want tokens data[1] : //user shares withdrawAmount * data[3] / data[2], //amt * totalShares / wantLockedTotal "" ); } else if (vaultHealer.balanceOf(address(this), vid) == 0) return; vaultHealer.withdraw(vid, type(uint).max, ""); if (vid > 2**16) quartzOut(vid >> 16, 0); IWETH weth = router.WETH(); if (isPair) { IERC20 token0 = pair.token0(); IERC20 token1 = pair.token1(); if (token0 != weth && token1 != weth) { LibQuartz.removeLiquidity(pair, msg.sender); } else { LibQuartz.removeLiquidity(pair, address(this)); returnAsset(token0, weth); //returns any leftover tokens to user returnAsset(token1, weth); //returns any leftover tokens to user } } else { returnAsset(pair, weth); } } function _swapAndStake(uint vid, uint256 tokenAmountOutMin, IERC20 tokenIn) private { (IUniRouter router,,IUniPair pair, bool isPair) = vaultHealer.getRouterAndPair(vid); IWETH weth = router.WETH(); if (isPair) { IERC20 token0 = pair.token0(); IERC20 token1 = pair.token1(); //_approveTokenIfNeeded(tokenIn, router); if (token0 == tokenIn) { (uint256 reserveA, uint256 reserveB,) = pair.getReserves(); LibQuartz.swapDirect(router, LibQuartz.getSwapAmount(router, tokenIn.balanceOf(address(this)), reserveA, reserveB), tokenIn, token1, tokenAmountOutMin); } else if (token1 == tokenIn) { (uint256 reserveA, uint256 reserveB,) = pair.getReserves(); LibQuartz.swapDirect(router, LibQuartz.getSwapAmount(router, tokenIn.balanceOf(address(this)), reserveB, reserveA), tokenIn, token0, tokenAmountOutMin); } else { uint swapAmountIn = tokenIn.balanceOf(address(this))/2; if(LibQuartz.hasSufficientLiquidity(token0, tokenIn, router, MINIMUM_AMOUNT)) { LibQuartz.swapDirect(router, swapAmountIn, tokenIn, token0, tokenAmountOutMin); } else { LibQuartz.swapViaToken(router, swapAmountIn, tokenIn, weth, token0, tokenAmountOutMin); } if(LibQuartz.hasSufficientLiquidity(token1, tokenIn, router, MINIMUM_AMOUNT)) { LibQuartz.swapDirect(router, swapAmountIn, tokenIn, token1, tokenAmountOutMin); } else { LibQuartz.swapViaToken(router, swapAmountIn, tokenIn, weth, token1, tokenAmountOutMin); } returnAsset(tokenIn, weth); } LibQuartz.optimalMint(pair, token0, token1); returnAsset(token0, weth); returnAsset(token1, weth); } else { uint swapAmountIn = tokenIn.balanceOf(address(this)); if(LibQuartz.hasSufficientLiquidity(pair, tokenIn, router, MINIMUM_AMOUNT)) { LibQuartz.swapDirect(router, swapAmountIn, tokenIn, pair, tokenAmountOutMin); } else { LibQuartz.swapViaToken(router, swapAmountIn, tokenIn, weth, pair, tokenAmountOutMin); } returnAsset(tokenIn, weth); } _approveTokenIfNeeded(pair); uint balance = pair.balanceOf(address(this)); vaultHealer.deposit(vid, balance, ""); balance = vaultHealer.balanceOf(address(this), vid); vaultHealer.safeTransferFrom(address(this), msg.sender, vid, balance, ""); } function returnAsset(IERC20 token, IWETH weth) internal { uint256 balance = token.balanceOf(address(this)); if (balance == 0) return; if (token == weth) { weth.withdraw(balance); (bool success,) = msg.sender.call{value: address(this).balance}(new bytes(0)); require(success, 'Quartz: ETH transfer failed'); } else { token.safeTransfer(msg.sender, balance); } } function _approveTokenIfNeeded(IERC20 token) private { if (!approvals[token]) { token.safeApprove(address(vaultHealer), type(uint256).max); approvals[token] = true; } } function asSingletonArray(uint256 n) internal pure returns (uint256[] memory tempArray) { tempArray = new uint256[](1); tempArray[0] = n; } //This contract should not hold ERC20 tokens at the end of a transaction. If this happens due to some error, this will send the //tokens to the treasury if it is set. Contact the team for help, and maybe they can return your missing token! function rescue(IERC20 token) external { (address receiver,) = vaultHealer.vaultFeeManager().getWithdrawFee(0); if (receiver == address(0)) receiver = msg.sender; token.transfer(receiver, token.balanceOf(address(this))); } }
// SPDX-License-Identifier: GPLv2 // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // @author Wivern for Beefy.Finance, ToweringTopaz for Crystl.Finance // @notice This contract adds liquidity to Uniswap V2 compatible liquidity pair pools and stake. pragma solidity ^0.8.14; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./VaultChonk.sol"; import "../interfaces/IUniRouter.sol"; library LibQuartz { using SafeERC20 for IERC20; using SafeERC20 for IUniPair; using VaultChonk for IVaultHealer; uint256 constant MINIMUM_AMOUNT = 1000; function getRouter(IVaultHealer vaultHealer, uint vid) internal view returns (IUniRouter) { return vaultHealer.strat(vid).router(); } function getRouterAndPair(IVaultHealer vaultHealer, uint _vid) internal view returns (IUniRouter router, IStrategy strat, IUniPair pair, bool valid) { strat = vaultHealer.strat(_vid); router = strat.router(); pair = IUniPair(address(strat.wantToken())); try pair.factory() returns (IUniFactory _f) { valid = _f == router.factory(); require(valid, "Quartz: This vault cannot be zapped"); //Risk of illiquid pair loss here, so we shouldn't zap } catch { } } function getSwapAmount(IUniRouter router, uint256 investmentA, uint256 reserveA, uint256 reserveB) internal pure returns (uint256 swapAmount) { uint256 halfInvestment = investmentA / 2; uint256 numerator = router.getAmountOut(halfInvestment, reserveA, reserveB); uint256 denominator = router.quote(halfInvestment, reserveA + halfInvestment, reserveB - numerator); swapAmount = investmentA - sqrt(halfInvestment * halfInvestment * numerator / denominator); } function returnAssets(IUniRouter router, IERC20[] memory tokens) internal { IWETH weth = router.WETH(); for (uint256 i; i < tokens.length; i++) { uint256 balance = tokens[i].balanceOf(address(this)); if (balance == 0) continue; if (tokens[i] == weth) { weth.withdraw(balance); (bool success,) = msg.sender.call{value: balance}(new bytes(0)); require(success, 'Quartz: ETH transfer failed'); } else { tokens[i].safeTransfer(msg.sender, balance); } } } function swapDirect( IUniRouter _router, uint256 _amountIn, IERC20 input, IERC20 output, uint amountOutMin ) public returns (uint amountOutput) { IUniFactory factory = _router.factory(); IUniPair pair = factory.getPair(input, output); input.safeTransfer(address(pair), _amountIn); uint balanceBefore = output.balanceOf(address(this)); bool inputIsToken0 = input < output; (uint reserve0, uint reserve1,) = pair.getReserves(); (uint reserveInput, uint reserveOutput) = inputIsToken0 ? (reserve0, reserve1) : (reserve1, reserve0); uint amountInput = input.balanceOf(address(pair)) - reserveInput; amountOutput = _router.getAmountOut(amountInput, reserveInput, reserveOutput); (uint amount0Out, uint amount1Out) = inputIsToken0 ? (uint(0), amountOutput) : (amountOutput, uint(0)); pair.swap(amount0Out, amount1Out, address(this), ""); if (output.balanceOf(address(this)) <= amountOutMin + balanceBefore) { unchecked { revert IStrategy.InsufficientOutputAmount(output.balanceOf(address(this)) - balanceBefore, amountOutMin); } } } function swapViaToken( IUniRouter _router, uint256 _amountIn, IERC20 input, IERC20 middle, IERC20 output, uint amountOutMin ) public returns (uint amountOutput) { IUniFactory factory = _router.factory(); IUniPair pairA = factory.getPair(input, middle); IUniPair pairB = factory.getPair(middle, output); input.safeTransfer(address(pairA), _amountIn); uint balanceBefore = output.balanceOf(address(this)); { { (uint reserve0, uint reserve1,) = pairA.getReserves(); (uint reserveInput, uint reserveOutput) = (input < middle) ? (reserve0, reserve1) : (reserve1, reserve0); uint amountInput = input.balanceOf(address(pairA)) - reserveInput; amountOutput = _router.getAmountOut(amountInput, reserveInput, reserveOutput); } (uint amount0Out, uint amount1Out) = (input < middle) ? (uint(0), amountOutput) : (amountOutput, uint(0)); pairA.swap(amount0Out, amount1Out, address(pairB), ""); } { { (uint reserve0, uint reserve1,) = pairB.getReserves(); (uint reserveInput, uint reserveOutput) = (middle < output) ? (reserve0, reserve1) : (reserve1, reserve0); uint amountInput = middle.balanceOf(address(pairB)) - reserveInput; amountOutput = _router.getAmountOut(amountInput, reserveInput, reserveOutput); } (uint amount0Out, uint amount1Out) = (middle < output) ? (uint(0), amountOutput) : (amountOutput, uint(0)); pairB.swap(amount0Out, amount1Out, address(this), ""); } if (output.balanceOf(address(this)) <= amountOutMin + balanceBefore) { unchecked { revert IStrategy.InsufficientOutputAmount(output.balanceOf(address(this)) - balanceBefore, amountOutMin); } } } function estimateSwap(IVaultHealer vaultHealer, uint pid, IERC20 tokenIn, uint256 fullInvestmentIn) public view returns(uint256 swapAmountIn, uint256 swapAmountOut, IERC20 swapTokenOut) { (IUniRouter router,,IUniPair pair,bool isPair) = getRouterAndPair(vaultHealer, pid); require(isPair, "Quartz: Cannot estimate swap for non-LP token"); IERC20 token0 = pair.token0(); (uint256 reserveA, uint256 reserveB,) = pair.getReserves(); if (token0 == tokenIn) { swapTokenOut = pair.token1(); } else { require(pair.token1() == tokenIn, 'Quartz: Input token not present in liquidity pair'); swapTokenOut = token0; (reserveA, reserveB) = (reserveB, reserveA); } swapAmountIn = getSwapAmount(router, fullInvestmentIn, reserveA, reserveB); swapAmountOut = router.getAmountOut(swapAmountIn, reserveA, reserveB); } function removeLiquidity(IUniPair pair, address to) internal { uint balance = pair.balanceOf(address(this)); if (balance == 0) return; pair.safeTransfer(address(pair), balance); (uint256 amount0, uint256 amount1) = pair.burn(to); require(amount0 >= MINIMUM_AMOUNT, 'Quartz: INSUFFICIENT_A_AMOUNT'); require(amount1 >= MINIMUM_AMOUNT, 'Quartz: INSUFFICIENT_B_AMOUNT'); } function optimalMint(IUniPair pair, IERC20 token0, IERC20 token1) public returns (uint liquidity) { (token0, token1) = token0 < token1 ? (token0, token1) : (token1, token0); pair.skim(address(this)); (uint112 reserve0, uint112 reserve1,) = pair.getReserves(); uint balance0 = token0.balanceOf(address(this)); uint balance1 = token1.balanceOf(address(this)); if (balance0 * reserve1 < balance1 * reserve0) { balance1 = balance0 * reserve1 / reserve0; } else { balance0 = balance1 * reserve0 / reserve1; } token0.safeTransfer(address(pair), balance0); token1.safeTransfer(address(pair), balance1); liquidity = pair.mint(address(this)); } function hasSufficientLiquidity(IERC20 token0, IERC20 token1, IUniRouter router, uint256 min_amount) internal view returns (bool hasLiquidity) { IUniFactory factory = router.factory(); IUniPair pair = IUniPair(factory.getPair(token0, token1)); if (address(pair) == address(0)) return false; //pair hasn't been created, so zero liquidity (uint256 reserveA, uint256 reserveB,) = pair.getReserves(); return reserveA > min_amount && reserveB > min_amount; } // credit for this implementation goes to // https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687 function sqrt(uint256 x) internal pure returns (uint256) { unchecked { //impossible for any of this to overflow if (x == 0) return 0; // this block is equivalent to r = uint256(1) << (BitMath.mostSignificantBit(x) / 2); // however that code costs significantly more gas uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return (r < r1 ? r : r1); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.14; import "../interfaces/IVaultHealer.sol"; import "../interfaces/IBoostPool.sol"; import "./Cavendish.sol"; import "@openzeppelin/contracts/utils/structs/BitMaps.sol"; library VaultChonk { using BitMaps for BitMaps.BitMap; event AddVault(uint indexed vid); event AddBoost(uint indexed boostid); function createVault(mapping(uint => IVaultHealer.VaultInfo) storage vaultInfo, uint vid, IStrategy _implementation, bytes calldata data) external { addVault(vaultInfo, vid, _implementation, data); } function createMaximizer(mapping(uint => IVaultHealer.VaultInfo) storage vaultInfo, uint targetVid, bytes calldata data) external returns (uint vid) { if (targetVid >= 2**208) revert IVaultHealer.MaximizerTooDeep(targetVid); IVaultHealer.VaultInfo storage targetVault = vaultInfo[targetVid]; uint16 nonce = targetVault.numMaximizers + 1; vid = (targetVid << 16) | nonce; targetVault.numMaximizers = nonce; addVault(vaultInfo, vid, strat(targetVid).getMaximizerImplementation(), data); } function addVault(mapping(uint => IVaultHealer.VaultInfo) storage vaultInfo, uint256 vid, IStrategy implementation, bytes calldata data) private { // if (!implementation.supportsInterface(type(IStrategy).interfaceId) //doesn't support interface || implementation.implementation() != implementation //is proxy ) revert IVaultHealer.NotStrategyImpl(implementation); IVaultHealer implVaultHealer = implementation.vaultHealer(); if (address(implVaultHealer) != address(this)) revert IVaultHealer.ImplWrongHealer(implVaultHealer); IStrategy _strat = IStrategy(Cavendish.clone(address(implementation), bytes32(uint(vid)))); _strat.initialize(abi.encodePacked(vid, data)); vaultInfo[vid].want = _strat.wantToken(); vaultInfo[vid].active = true; //uninitialized vaults are paused; this unpauses emit AddVault(vid); } function createBoost(mapping(uint => IVaultHealer.VaultInfo) storage vaultInfo, BitMaps.BitMap storage activeBoosts, uint vid, address _implementation, bytes calldata initdata) external { if (vid >= 2**224) revert IVaultHealer.MaximizerTooDeep(vid); IVaultHealer.VaultInfo storage vault = vaultInfo[vid]; uint16 nonce = vault.numBoosts; vault.numBoosts = nonce + 1; uint _boostID = (uint(bytes32(bytes4(0xB0057000 + nonce))) | vid); IBoostPool _boost = IBoostPool(Cavendish.clone(_implementation, bytes32(_boostID))); _boost.initialize(msg.sender, _boostID, initdata); activeBoosts.set(_boostID); emit AddBoost(_boostID); } //Computes the strategy address for any vid based on this contract's address and the vid's numeric value function strat(uint vid) internal view returns (IStrategy) { if (vid == 0) revert IVaultHealer.VidOutOfRange(0); return IStrategy(Cavendish.computeAddress(bytes32(vid))); } function strat(IVaultHealer vaultHealer, uint256 vid) internal pure returns (IStrategy) { if (vid == 0) revert IVaultHealer.VidOutOfRange(0); return IStrategy(Cavendish.computeAddress(bytes32(vid), address(vaultHealer))); } function boostInfo( uint16 len, BitMaps.BitMap storage activeBoosts, BitMaps.BitMap storage userBoosts, address account, uint vid ) external view returns ( IVaultHealer.BoostInfo[][3] memory boosts //active, finished, available ) { //Create bytes array indicating status of each boost pool and total number for each status bytes memory statuses = new bytes(len); uint numActive; uint numFinished; uint numAvailable; for (uint16 i; i < len; i++) { uint id = uint(bytes32(bytes4(0xB0057000 + i))) | vid; bytes1 status; if (userBoosts.get(id)) status = 0x01; //pool active for user if (activeBoosts.get(id) && boostPool(id).isActive()) status |= 0x02; //pool still paying rewards if (status == 0x00) continue; //pool finished, user isn't in, nothing to do else if (status == 0x01) numFinished++; //user in finished pool else if (status == 0x02) numAvailable++; //user not in active pool else numActive++; //user in active pool statuses[i] = status; } boosts[0] = new IVaultHealer.BoostInfo[](numActive); boosts[1] = new IVaultHealer.BoostInfo[](numFinished); boosts[2] = new IVaultHealer.BoostInfo[](numAvailable); uint[3] memory infoIndex; for (uint16 i; i < len; i++) { uint8 status = uint8(statuses[i]); if (status == 0) continue; //pool is done and user isn't in status %= 3; (uint boostID, IBoostPool pool) = boostPoolVid(vid, i); IVaultHealer.BoostInfo memory info = boosts[status][infoIndex[status]++]; //reference to the output array member where we will be storing the data info.id = boostID; (info.rewardToken, info.pendingReward) = pool.pendingReward(account); } } function boostPool(uint _boostID) internal view returns (IBoostPool) { return IBoostPool(Cavendish.computeAddress(bytes32(_boostID))); } function boostPoolVid(uint vid, uint16 n) internal view returns (uint, IBoostPool) { uint _boostID = (uint(bytes32(bytes4(0xB0057000 + n))) | vid); return (_boostID, boostPool(_boostID)); } function sizeOf(address _contract) external view returns (uint256 size) { assembly ("memory-safe") { size := extcodesize(_contract) } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.4; import "./IUniFactory.sol"; import "./IWETH.sol"; interface IUniRouter { function factory() external pure returns (IUniFactory); function WETH() external pure returns (IWETH); function addLiquidity( IERC20 tokenA, IERC20 tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns ( uint256 amountA, uint256 amountB, uint256 liquidity ); function addLiquidityETH( IERC20 token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable returns ( uint256 amountToken, uint256 amountETH, uint256 liquidity ); function removeLiquidity( IERC20 tokenA, IERC20 tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( IERC20 token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); function removeLiquidityWithPermit( IERC20 tokenA, IERC20 tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETHWithPermit( IERC20 token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountToken, uint256 amountETH); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, IERC20[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, IERC20[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactETHForTokens( uint256 amountOutMin, IERC20[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function swapTokensForExactETH( uint256 amountOut, uint256 amountInMax, IERC20[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, IERC20[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapETHForExactTokens( uint256 amountOut, IERC20[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) external pure returns (uint256 amountB); function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountOut); function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountIn); function getAmountsOut(uint256 amountIn, IERC20[] calldata path) external view returns (uint256[] memory amounts); function getAmountsIn(uint256 amountOut, IERC20[] calldata path) external view returns (uint256[] memory amounts); function removeLiquidityETHSupportingFeeOnTransferTokens( IERC20 token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( IERC20 token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, IERC20[] calldata path, address to, uint256 deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, IERC20[] calldata path, address to, uint256 deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, IERC20[] calldata path, address to, uint256 deadline ) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IStrategy.sol"; import "./IVaultFeeManager.sol"; import "@openzeppelin/contracts/access/IAccessControl.sol"; import "./IBoostPool.sol"; import "../libraries/Cavendish.sol"; ///@notice Interface for the Crystl v3 Vault central contract interface IVaultHealer is IERC1155 { event AddVault(uint indexed vid); event Paused(uint indexed vid); event Unpaused(uint indexed vid); event Deposit(address indexed account, uint256 indexed vid, uint256 amount); event Withdraw(address indexed from, address indexed to, uint256 indexed vid, uint256 amount); event Earned(uint256 indexed vid, uint256 wantLockedTotal, uint256 totalSupply); event AddBoost(uint indexed boostid); event EnableBoost(address indexed user, uint indexed boostid); event BoostEmergencyWithdraw(address user, uint _boostID); event SetAutoEarn(uint indexed vid, bool earnBeforeDeposit, bool earnBeforeWithdraw); event FailedEarn(uint indexed vid, string reason); event FailedEarnBytes(uint indexed vid, bytes reason); event FailedWithdrawFee(uint indexed vid, string reason); event FailedWithdrawFeeBytes(uint indexed vid, bytes reason); event MaximizerHarvest(address indexed account, uint indexed vid, uint targetShares); error PausedError(uint256 vid); //Action cannot be completed on a paused vid error MaximizerTooDeep(uint256 targetVid); //Too many layers of nested maximizers (13 is plenty I should hope) error VidOutOfRange(uint256 vid); //Specified vid does not represent an existing vault error PanicCooldown(uint256 expiry); //Cannot panic this vault again until specified time error InvalidFallback(); //The fallback function should not be called in this context error WithdrawZeroBalance(address from); //User attempting to withdraw from a vault when they have zero shares error UnauthorizedPendingDepositAmount(); //Strategy attempting to pull more tokens from the user than authorized error RestrictedFunction(bytes4 selector); error NotStrategyImpl(IStrategy implementation); error ImplWrongHealer(IVaultHealer implHealer); //Attempting to use a strategy configured for another VH, not this one error InsufficientBalance(IERC20 token, address from, uint balance, uint requested); error InsufficientApproval(IERC20 token, address from, uint available, uint requested); error NotApprovedToEnableBoost(address account, address operator); error BoostPoolNotActive(uint256 _boostID); error BoostPoolAlreadyJoined(address account, uint256 _boostID); error BoostPoolNotJoined(address account, uint256 _boostID); error ArrayMismatch(uint lenA, uint lenB); error ERC1167_Create2Failed(); //Low-level error with creating a strategy proxy error ERC1167_ImplZeroAddress(); //If attempting to deploy a strategy with a zero implementation address ///@notice This is used solely by strategies to indirectly pull ERC20 tokens. function executePendingDeposit(address _to, uint192 _amount) external; ///@notice This is used solely by maximizer strategies to deposit their earnings function maximizerDeposit(uint256 _vid, uint256 _wantAmt, bytes calldata _data) external payable; ///@notice Compounds the listed vaults. Generally only needs to be called by an optimized earn script, not frontend users. Earn is triggered automatically on deposit and withdraw by default. function earn(uint256[] calldata vids) external returns (uint[] memory successGas); function earn(uint256[] calldata vids, bytes[] calldata data) external returns (uint[] memory successGas); ////Functions for users and frontend developers are below ///@notice Standard withdraw for msg.sender function withdraw(uint256 _vid, uint256 _wantAmt, bytes calldata _data) external; ///@notice Withdraw with custom to account function withdraw(uint256 _vid, uint256 _wantAmt, address _to, bytes calldata _data) external; function deposit(uint256 _vid, uint256 _wantAmt, bytes calldata _data) external payable; function totalSupply(uint256 vid) external view returns (uint256); ///@notice This returns the strategy address for any vid. ///@dev For dapp or contract usage, it may be better to calculate strategy addresses locally. The formula is in the function Cavendish.computeAddress //function strat(uint256 _vid) external view returns (IStrategy); struct VaultInfo { IERC20 want; uint8 noAutoEarn; bool active; //not paused uint48 lastEarnBlock; uint16 numBoosts; uint16 numMaximizers; //number of maximizer vaults pointing here. For vid 0x0045, its maximizer will be 0x00450001, 0x00450002, ... } function vaultInfo(uint vid) external view returns (IERC20, uint8, bool, uint48,uint16,uint16); function tokenData(address account, uint[] calldata vids) external view returns (uint[4][] memory data); //@notice Returns the number of non-maximizer vaults, where the want token is compounded within one strategy function numVaultsBase() external view returns (uint16); ///@notice The number of shares in a maximizer's target vault pending to a user account from said maximizer ///@param _account Some user account ///@param _vid The vid of the maximizer ///@dev The vid of the target is implied to be _vid >> 16 function maximizerPendingTargetShares(address _account, uint256 _vid) external view returns (uint256); ///@notice The balance of a user's shares in a vault, plus any pending shares from maximizers function totalBalanceOf(address _account, uint256 _vid) external view returns (uint256 amount); ///@notice Harvests a single maximizer ///@param _vid The vid of the maximizer vault, which deposits into some other target function harvestMaximizer(uint256 _vid) external; ///@notice Harvests all maximizers earning to the specified target vid ///@param _vid The vid of the target vault, to which many maximizers may deposit function harvestTarget(uint256 _vid) external; ///@notice This can be used to make two or more calls to the contract as an atomic transaction. ///@param inputs are the standard abi-encoded function calldata with selector. This can be any external function on vaultHealer. //function multicall(bytes[] calldata inputs) external returns (bytes[] memory); struct BoostInfo { uint id; IBoostPool pool; IERC20 rewardToken; uint pendingReward; } function vaultFeeManager() external view returns (IVaultFeeManager); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IBoostPool { function bonusEndBlock() external view returns (uint32); function BOOST_ID() external view returns (uint256); function joinPool(address _user, uint112 _amount) external; function harvest(address) external; function emergencyWithdraw(address _user) external returns (bool success); function notifyOnTransfer(address _from, address _to, uint256 _amount) external returns (bool poolDone); function initialize(address _owner, uint256 _boostID, bytes calldata initdata) external; function pendingReward(address _user) external view returns (IERC20 token, uint256 amount); function isActive() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.14; /// @title Cavendish clones /// @author ToweringTopaz /// @notice Creates ERC-1167 minimal proxies whose addresses depend only on the salt and deployer address /// @dev See _fallback for important instructions library Cavendish { /* Proxy init bytecode: 11 bytes: 602d80343434335afa15f3 60 push1 2d : size 80 dup1 : size size 34 callvalue : 0 size size 34 callvalue : 0 0 size size 34 callvalue : 0 0 0 size size 33 caller : caller 0 0 0 size size 5a gas : gas caller 0 0 0 size size fa staticcall : success size 15 iszero : 0 size f3 return : */ bytes11 constant PROXY_INIT_CODE = hex'602d80343434335afa15f3'; //below is keccak256(abi.encodePacked(PROXY_INIT_CODE)); bytes32 constant PROXY_INIT_HASH = hex'577cbdbf32026552c0ae211272febcff3ea352b0c755f8f39b49856dcac71019'; error ERC1167_Create2Failed(); error ERC1167_ImplZeroAddress(); /// @notice Creates an 1167-compliant minimal proxy whose address is purely a function of the deployer address and the salt /// @param _implementation The contract to be cloned /// @param salt Used to determine and calculate the proxy address /// @return Address of the deployed proxy function clone(address _implementation, bytes32 salt) internal returns (address) { if (_implementation == address(0)) revert ERC1167_ImplZeroAddress(); address instance; assembly ("memory-safe") { sstore(PROXY_INIT_HASH, shl(96, _implementation)) //store at slot PROXY_INIT_HASH which should be empty mstore(0, PROXY_INIT_CODE) instance := create2(0, 0x00, 11, salt) sstore(PROXY_INIT_HASH, 0) } if (instance == address(0)) revert ERC1167_Create2Failed(); return instance; } //Standard function to compute a create2 address deployed by this address, but not impacted by the target implemention function computeAddress(bytes32 salt) internal view returns (address) { return computeAddress(salt, address(this)); } //Standard function to compute a create2 address, but not impacted by the target implemention function computeAddress( bytes32 salt, address deployer ) internal pure returns (address) { bytes32 _data = keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, PROXY_INIT_HASH)); return address(uint160(uint256(_data))); } /// @notice Called by the proxy constructor to provide the bytecode for the final proxy contract. /// @dev Deployer contracts must call Cavendish._fallback() in their own fallback functions. /// Generally compatible with contracts that use fallback functions. Simply call this at the /// top of your fallback, and it will run only when needed. function _fallback() internal view { assembly ("memory-safe") { if iszero(extcodesize(caller())) { //will be, for a contract under construction let _implementation := sload(PROXY_INIT_HASH) if gt(_implementation, 0) { mstore(0x00, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000) mstore(0x0a, _implementation) mstore(0x1e, 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) return(0x00, 0x2d) //Return to external caller, not to any internal function } } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/structs/BitMaps.sol) pragma solidity ^0.8.0; /** * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. * Largelly inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. */ library BitMaps { struct BitMap { mapping(uint256 => uint256) _data; } /** * @dev Returns whether the bit at `index` is set. */ function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); return bitmap._data[bucket] & mask != 0; } /** * @dev Sets the bit at `index` to the boolean `value`. */ function setTo( BitMap storage bitmap, uint256 index, bool value ) internal { if (value) { set(bitmap, index); } else { unset(bitmap, index); } } /** * @dev Sets the bit at `index`. */ function set(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] |= mask; } /** * @dev Unsets the bit at `index`. */ function unset(BitMap storage bitmap, uint256 index) internal { uint256 bucket = index >> 8; uint256 mask = 1 << (index & 0xff); bitmap._data[bucket] &= ~mask; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC1155/IERC1155.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC1155 compliant contract, as defined in the * https://eips.ethereum.org/EIPS/eip-1155[EIP]. * * _Available since v3.1._ */ interface IERC1155 is IERC165 { /** * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. */ event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); /** * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all * transfers. */ event TransferBatch( address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values ); /** * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to * `approved`. */ event ApprovalForAll(address indexed account, address indexed operator, bool approved); /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. * * If an {URI} event was emitted for `id`, the standard * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value * returned by {IERC1155MetadataURI-uri}. */ event URI(string value, uint256 indexed id); /** * @dev Returns the amount of tokens of token type `id` owned by `account`. * * Requirements: * * - `account` cannot be the zero address. */ function balanceOf(address account, uint256 id) external view returns (uint256); /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. * * Requirements: * * - `accounts` and `ids` must have the same length. */ function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory); /** * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, * * Emits an {ApprovalForAll} event. * * Requirements: * * - `operator` cannot be the caller. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. * * See {setApprovalForAll}. */ function isApprovedForAll(address account, address operator) external view returns (bool); /** * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. * * Emits a {TransferSingle} event. * * Requirements: * * - `to` cannot be the zero address. * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}. * - `from` must have a balance of tokens of type `id` of at least `amount`. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the * acceptance magic value. */ function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes calldata data ) external; /** * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. * * Emits a {TransferBatch} event. * * Requirements: * * - `ids` and `amounts` must have the same length. * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the * acceptance magic value. */ function safeBatchTransferFrom( address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data ) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.13; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IUniRouter.sol"; import "../libraries/Fee.sol"; import "../libraries/Tactics.sol"; import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import "./IMagnetite.sol"; import "./IVaultHealer.sol"; interface IStrategy is IERC165 { error Muppet(address caller); error IdenticalAddresses(IERC20 a, IERC20 b); error ZeroAddress(); error InsufficientOutputAmount(uint amountOut, uint amountOutMin); error Strategy_CriticalMemoryError(uint ptr); error Strategy_Improper1155Deposit(address operator, address from, uint id); error Strategy_Improper1155BatchDeposit(address operator, address from, uint[] ids); error Strategy_ImproperEthDeposit(address sender, uint amount); error Strategy_NotVaultHealer(address sender); error Strategy_InitializeOnlyByProxy(); error Strategy_ExcessiveFarmSlippage(); error Strategy_WantLockedLoss(); error Strategy_TotalSlippageWithdrawal(); //nothing to withdraw after slippage error Strategy_DustDeposit(uint256 wantAdded); //Deposit amount is insignificant after slippage function initialize (bytes calldata data) external; function wantToken() external view returns (IERC20); // Want address function wantLockedTotal() external view returns (uint256); // Total want tokens managed by strategy (vaultSharesTotal + want token balance) function vaultSharesTotal() external view returns (uint256); //Want tokens deposited in strategy's pool function earn(Fee.Data[3] memory fees, address _operator, bytes calldata _data) external returns (bool success, uint256 _wantLockedTotal); // Main want token compounding function function deposit(uint256 _wantAmt, uint256 _sharesTotal, bytes calldata _data) external payable returns (uint256 wantAdded, uint256 sharesAdded); function withdraw(uint256 _wantAmt, uint256 _userShares, uint256 _sharesTotal, bytes calldata _data) external returns (uint256 sharesRemoved, uint256 wantAmt); function panic() external; function unpanic() external; function router() external view returns (IUniRouter); // Univ2 router used by this strategy function vaultHealer() external view returns (IVaultHealer); function implementation() external view returns (IStrategy); function isMaximizer() external view returns (bool); function getMaximizerImplementation() external view returns (IStrategy); struct ConfigInfo { uint256 vid; IERC20 want; uint256 wantDust; address masterchef; uint pid; IUniRouter _router; IMagnetite _magnetite; IERC20[] earned; uint256[] earnedDust; uint slippageFactor; bool feeOnTransfer; } function configInfo() external view returns (ConfigInfo memory); function tactics() external view returns (Tactics.TacticsA tacticsA, Tactics.TacticsB tacticsB); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.0; import "../libraries/Fee.sol"; interface IVaultFeeManager { function getEarnFees(uint vid) external view returns (Fee.Data[3] memory fees); function getWithdrawFee(uint vid) external view returns (address receiver, uint16 rate); function getEarnFees(uint[] calldata vids) external view returns (Fee.Data[3][] memory fees); function getWithdrawFees(uint[] calldata vids) external view returns (Fee.Data[] memory fees); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: GPLv2 pragma solidity ^0.8.14; import "../interfaces/IWETH.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; library Fee { using Fee for Data; using Fee for Data[3]; type Data is uint256; uint256 constant FEE_MAX = 3000; // 100 = 1% : basis points function rate(Data _fee) internal pure returns (uint16) { return uint16(Data.unwrap(_fee)); } function receiver(Data _fee) internal pure returns (address) { return address(uint160(Data.unwrap(_fee) >> 16)); } function receiverAndRate(Data _fee) internal pure returns (address, uint16) { uint fee = Data.unwrap(_fee); return (address(uint160(fee >> 16)), uint16(fee)); } function create(address _receiver, uint16 _rate) internal pure returns (Data) { return Data.wrap((uint256(uint160(_receiver)) << 16) | _rate); } function totalRate(Data[3] calldata _fees) internal pure returns (uint16 total) { unchecked { //overflow is impossible if Fee.Data are valid total = uint16(Data.unwrap(_fees[0]) + Data.unwrap(_fees[1]) + Data.unwrap(_fees[2])); require(total <= FEE_MAX, "Max total fee of 30%"); } } function check(Data[3] memory _fees, uint maxTotal) internal pure returns (uint16 total) { unchecked { //overflow is impossible if Fee.Data are valid total = uint16(Data.unwrap(_fees[0]) + Data.unwrap(_fees[1]) + Data.unwrap(_fees[2])); require(total <= maxTotal, "Max total fee exceeded"); } } //Token amount is all fees function payTokenFeeAll(Data[3] calldata _fees, IERC20 _token, uint _tokenAmt) internal { if (_tokenAmt == 0) return; uint feeTotalRate = totalRate(_fees); for (uint i; i < 3; i++) { (address _receiver, uint _rate) = Fee.receiverAndRate(_fees[i]); if (_receiver == address(0) || _rate == 0) break; SafeERC20.safeTransfer(_token, _receiver, _tokenAmt * _rate / feeTotalRate); } } //Amount includes fee and non-fee portions function payTokenFeePortion(Data[3] calldata _fees, IERC20 _token, uint _tokenAmt) internal returns (uint amtAfter) { if (_tokenAmt == 0) return 0; amtAfter = _tokenAmt; uint feeTotalRate = totalRate(_fees); uint feeTotalAmt = feeTotalRate * _tokenAmt / 10000; for (uint i; i < 3; i++) { (address _receiver, uint _rate) = Fee.receiverAndRate(_fees[i]); if (_receiver == address(0) || _rate == 0) break; uint amount = _tokenAmt * _rate / 10000; SafeERC20.safeTransfer(_token, _receiver, amount); } return _tokenAmt - feeTotalAmt; } //Use this if ethAmt is all fees function payEthAll(Data[3] calldata _fees, uint _ethAmt) internal { if (_ethAmt == 0) return; uint feeTotalRate = totalRate(_fees); for (uint i; i < 3; i++) { (address _receiver, uint _rate) = Fee.receiverAndRate(_fees[i]); if (_receiver == address(0) || _rate == 0) break; (bool success,) = _receiver.call{value: _ethAmt * _rate / feeTotalRate, gas: 0x40000}(""); require(success, "Fee: Transfer failed"); } } //Use this if ethAmt includes both fee and non-fee portions function payEthPortion(Data[3] calldata _fees, uint _ethAmt) internal returns (uint ethAfter) { ethAfter = _ethAmt; for (uint i; i < 3; i++) { (address _receiver, uint _rate) = Fee.receiverAndRate(_fees[i]); if (_receiver == address(0) || _rate == 0) break; uint amount = _ethAmt * _rate / 10000; (bool success,) = _receiver.call{value: amount, gas: 0x40000}(""); require(success, "Fee: Transfer failed"); ethAfter -= amount; } } function payWethPortion(Data[3] calldata _fees, IWETH weth, uint _wethAmt) internal returns (uint wethAfter) { uint feeTotalRate = totalRate(_fees); uint feeTotalAmt = feeTotalRate * _wethAmt / 10000; weth.withdraw(feeTotalAmt); for (uint i; i < 3; i++) { (address _receiver, uint _rate) = Fee.receiverAndRate(_fees[i]); if (_receiver == address(0) || _rate == 0) break; uint amount = _wethAmt * _rate / 10000; (bool success,) = _receiver.call{value: amount, gas: 0x40000}(""); require(success, "Fee: Transfer failed"); } return _wethAmt - feeTotalAmt; } function set(Data[3] storage _fees, address[3] memory _receivers, uint16[3] memory _rates) internal { uint feeTotal; for (uint i; i < 3; i++) { address _receiver = _receivers[i]; uint16 _rate = _rates[i]; require(_receiver != address(0) || _rate == 0, "Invalid treasury address"); feeTotal += _rate; uint256 _fee = uint256(uint160(_receiver)) << 16 | _rate; _fees[i] = Data.wrap(_fee); } require(feeTotal <= 3000, "Max total fee of 30%"); } function check(Data _fee, uint maxRate) internal pure { (address _receiver, uint _rate) = _fee.receiverAndRate(); if (_rate > 0) { require(_receiver != address(0), "Invalid treasury address"); require(_rate <= maxRate, "Max withdraw fee exceeded"); } } }
// SPDX-License-Identifier: GPLv2 pragma solidity ^0.8.14; import "@openzeppelin/contracts/utils/Address.sol"; /// @title Tactics /// @author ToweringTopaz /// @notice Provides a generic method which vault strategies can use to call deposit/withdraw/balance on stakingpool or masterchef-like contracts library Tactics { using Address for address; /* This library handles masterchef function call data packed as follows: uint256 tacticsA: 160: masterchef 24: pid 8: position of vaultSharesTotal function's returned amount within the returndata 32: selector for vaultSharesTotal 32: vaultSharesTotal encoded call format uint256 tacticsB: 32: deposit selector 32: deposit encoded call format 32: withdraw selector 32: withdraw encoded call format 32: harvest selector 32: harvest encoded call format 32: emergencyVaultWithdraw selector 32: emergencyVaultWithdraw encoded call format Encoded calls use function selectors followed by single nibbles as follows, with the output packed to 32 bytes: 0: end of line/null f: 32 bytes zero 4: specified amount 3: address(this) 2: pid */ type TacticsA is bytes32; type TacticsB is bytes32; function masterchef(TacticsA tacticsA) internal pure returns (address) { return address(bytes20(TacticsA.unwrap(tacticsA))); } function pid(TacticsA tacticsA) internal pure returns (uint24) { return uint24(bytes3(TacticsA.unwrap(tacticsA) << 160)); } function vaultSharesTotal(TacticsA tacticsA) internal view returns (uint256 amountStaked) { uint returnvarPosition = uint8(uint(TacticsA.unwrap(tacticsA)) >> 64); //where is our vaultshares in the return data uint64 encodedCall = uint64(uint(TacticsA.unwrap(tacticsA))); if (encodedCall == 0) return 0; bytes memory data = _generateCall(pid(tacticsA), encodedCall, 0); //pid, vst call, 0 data = masterchef(tacticsA).functionStaticCall(data, "Tactics: staticcall failed"); assembly ("memory-safe") { amountStaked := mload(add(data, add(0x20,returnvarPosition))) } } function deposit(TacticsA tacticsA, TacticsB tacticsB, uint256 amount) internal { _doCall(tacticsA, tacticsB, amount, 192); } function withdraw(TacticsA tacticsA, TacticsB tacticsB, uint256 amount) internal { _doCall(tacticsA, tacticsB, amount, 128); } function harvest(TacticsA tacticsA, TacticsB tacticsB) internal { _doCall(tacticsA, tacticsB, 0, 64); } function emergencyVaultWithdraw(TacticsA tacticsA, TacticsB tacticsB) internal { _doCall(tacticsA, tacticsB, 0, 0); } function _doCall(TacticsA tacticsA, TacticsB tacticsB, uint256 amount, uint256 offset) private { uint64 encodedCall = uint64(uint(TacticsB.unwrap(tacticsB)) >> offset); if (encodedCall == 0) return; bytes memory generatedCall = _generateCall(pid(tacticsA), encodedCall, amount); masterchef(tacticsA).functionCall(generatedCall, "Tactics: call failed"); } function _generateCall(uint24 _pid, uint64 encodedCall, uint amount) private view returns (bytes memory generatedCall) { generatedCall = abi.encodePacked(bytes4(bytes8(encodedCall))); for (bytes4 params = bytes4(bytes8(encodedCall) << 32); params != 0; params <<= 4) { bytes1 p = bytes1(params) & bytes1(0xf0); uint256 word; if (p == 0x20) { word = _pid; } else if (p == 0x30) { word = uint(uint160(address(this))); } else if (p == 0x40) { word = amount; } else if (p != 0xf0) { revert("Tactics: invalid tactic"); } generatedCall = abi.encodePacked(generatedCall, word); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.9; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IMagnetite { function findAndSavePath(address _router, IERC20 a, IERC20 b) external returns (IERC20[] memory path); function overridePath(address router, IERC20[] calldata _path) external; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IUniPair.sol"; interface IUniFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniPair pair); function allPairs(uint) external view returns (IUniPair pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (IUniPair pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint) external; }
// SPDX-License-Identifier: GPLv2 pragma solidity >=0.5.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./IUniFactory.sol"; interface IUniPair is IERC20 { function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (IUniFactory); function token0() external view returns (IERC20); function token1() external view returns (IERC20); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 1000000, "details": { "peephole": true, "inliner": true, "jumpdestRemover": true, "orderLiterals": true, "deduplicate": true, "cse": true, "constantOptimizer": true, "yul": true } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": { "contracts/libraries/LibQuartz.sol": { "LibQuartz": "0xe932f92d7e09c8742fa2e5293d9ff92364c053f5" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_vaultHealer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"vid","type":"uint256"}],"name":"VidOutOfRange","type":"error"},{"inputs":[],"name":"MINIMUM_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vid","type":"uint256"},{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"fullInvestmentIn","type":"uint256"}],"name":"estimateSwap","outputs":[{"internalType":"uint256","name":"swapAmountIn","type":"uint256"},{"internalType":"uint256","name":"swapAmountOut","type":"uint256"},{"internalType":"contract IERC20","name":"swapTokenOut","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vid","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOutMin","type":"uint256"},{"internalType":"contract IERC20","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"}],"name":"quartzIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vid","type":"uint256"},{"internalType":"uint256","name":"tokenAmountOutMin","type":"uint256"}],"name":"quartzInETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vid","type":"uint256"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"quartzOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"rescue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultHealer","outputs":[{"internalType":"contract IVaultHealer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a034620000a357601f620037e638819003918201601f19168301916001600160401b03831184841017620000a857808492602094604052833981010312620000a357516001600160a01b0381168103620000a3576001600160a01b03166080526040516137279081620000bf82396080518181816101f101528181610321015281816103d101528181610944015281816114070152818161193601526129780152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe60806040526004361015610023575b361561001957600080fd5b610021610a61565b005b6000803560e01c9081632201b7ba146100c657508063257d9bb8146100bd5780634f880c4b146100b45780637e2c5c19146100ab578063839006f2146100a2578063a111774d14610099578063f23a6e61146100905763f7bfff2a0361000e5761008b6108e6565b61000e565b5061008b61082b565b5061008b610605565b5061008b610345565b5061008b6102d5565b5061008b610175565b5061008b61011b565b346101085760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010857610103602435600435611405565b604051f35b80fd5b600091031261011657565b600080fd5b50346101165760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165760206040516103e88152f35b73ffffffffffffffffffffffffffffffffffffffff81160361011657565b50346101165760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576024356101b181610157565b604051907fed63953000000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff90817f00000000000000000000000000000000000000000000000000000000000000001660048401526004356024840152166044820152604435606482015260608160848173e932f92d7e09c8742fa2e5293d9ff92364c053f55af480156102c8575b60009081928291610292575b5060408051928352602083019390935273ffffffffffffffffffffffffffffffffffffffff1691810191909152606090f35b0390f35b905061028e92506102ba915060603d81116102c1575b6102b28183610b7e565b810190610be4565b909261025c565b503d6102a8565b6102d0610bd7565b610250565b50346101165760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011657602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5034610116576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576000906004359061038682610157565b6104fd816040938451907fe8da52b000000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff908383600481857f0000000000000000000000000000000000000000000000000000000000000000165afa9283156105f8575b88936105c9575b5086805180947f29c23e4a00000000000000000000000000000000000000000000000000000000825281858161044060048201906000602083019252565b0392165afa9283156105bc575b889361058c575b5081831615610584575b86517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152929116908383602481855afa928315610577575b8893610548575b508787518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801561053b575b61051157505051f35b8161053092903d10610534575b6105288183610b7e565b810190610e40565b5051f35b503d61051e565b610543610bd7565b610508565b610569919350843d8611610570575b6105618183610b7e565b810190610c05565b91386104a4565b503d610557565b61057f610bd7565b61049d565b33925061045e565b6105ad919350873d89116105b5575b6105a58183610b7e565b810190612bd2565b509138610454565b503d61059b565b6105c4610bd7565b61044d565b6105ea919350843d86116105f1575b6105e28183610b7e565b810190610bbf565b9138610402565b503d6105d8565b610600610bd7565b6103fb565b50346101165760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761002160443561064481610157565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152336004820152306024820152610779906064359060209073ffffffffffffffffffffffffffffffffffffffff8516908281604481855afa90811561081e575b600091610801575b506040517f70a0823100000000000000000000000000000000000000000000000000000000808252336004830152948482602481875afa9182156107f4575b6000926107d5575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81036107b55750839190808210156107ae57505b935b61073e6103e8861015610a6a565b61074a8530338a610db5565b60405190815230600482015291829060249082905afa9182156107a1575b600092610784575b50501015610d2a565b602435600435611932565b61079a9250803d10610570576105618183610b7e565b3880610770565b6107a9610bd7565b610768565b905061072e565b9490856107d0916107c98288961015610c14565b1015610c9f565b610730565b6107ed919250853d8711610570576105618183610b7e565b90386106f8565b6107fc610bd7565b6106f0565b6108189150833d8511610570576105618183610b7e565b386106b1565b610826610bd7565b6106a9565b50346101165760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165760043561086781610157565b610872602435610157565b60843567ffffffffffffffff80821161011657366023830112156101165781600401359081116101165736910160240111610116576108b361028e91611107565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576004356109226103e8341015610a6a565b73ffffffffffffffffffffffffffffffffffffffff60046020610981610968857f0000000000000000000000000000000000000000000000000000000000000000612bfc565b73ffffffffffffffffffffffffffffffffffffffff1690565b604051928380927fad5c46480000000000000000000000000000000000000000000000000000000082525afa908115610a54575b600091610a36575b5016803b1561011657610021916040517fd0e30db000000000000000000000000000000000000000000000000000000000815260008160048134875af18015610a29575b610a10575b5060243590611932565b80610a1d610a2392610b25565b8061010b565b38610a06565b610a31610bd7565b610a01565b610a4e915060203d81116105f1576105e28183610b7e565b386109bd565b610a5c610bd7565b6109b5565b333b1561011657565b15610a7157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f51756172747a3a20496e7369676e69666963616e7420696e70757420616d6f7560448201527f6e740000000000000000000000000000000000000000000000000000000000006064820152fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111610b3957604052565b610b41610af5565b604052565b6080810190811067ffffffffffffffff821117610b3957604052565b6040810190811067ffffffffffffffff821117610b3957604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b3957604052565b908160209103126101165751610bd481610157565b90565b506040513d6000823e3d90fd5b908160609103126101165780519160406020830151920151610bd481610157565b90816020910312610116575190565b15610c1b57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f51756172747a3a20496e70757420746f6b656e206973206e6f7420617070726f60448201527f76656400000000000000000000000000000000000000000000000000000000006064820152fd5b15610ca657565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f51756172747a3a20496e70757420746f6b656e2068617320696e73756666696360448201527f69656e742062616c616e636500000000000000000000000000000000000000006064820152fd5b15610d3157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f51756172747a3a204665652d6f6e2d7472616e736665722f7265666c6563742060448201527f746f6b656e73206e6f742079657420737570706f7274656400000000000000006064820152fd5b9092610e3193604051937f23b872dd00000000000000000000000000000000000000000000000000000000602086015273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a0820182811067ffffffffffffffff821117610e33575b604052610ee3565b565b610e3b610af5565b610e29565b90816020910312610116575180151581036101165790565b15610e5f57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff169060405190610f0782610b62565b6020928383527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656484840152803b15610f7e5760008281928287610f599796519301915af1610f53610fdc565b90611048565b80519081610f6657505050565b82610e3193610f79938301019101610e40565b610e58565b606484604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b3d15611043573d9067ffffffffffffffff8211611036575b6040519161102a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610b7e565b82523d6000602084013e565b61103e610af5565b610ff4565b606090565b90919015611054575090565b8151156110645750805190602001fd5b604051907f08c379a00000000000000000000000000000000000000000000000000000000082528160208060048301528251928360248401526000915b8483106110ee575050601f836044947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093116110e1575b01168101030190fd5b60008582860101526110d8565b81830181015186840160440152859350918201916110a1565b73ffffffffffffffffffffffffffffffffffffffff30911603611148577ff23a6e610000000000000000000000000000000000000000000000000000000090565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f51756172747a3a20496d70726f7065722045524331313535207472616e73666560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b60209067ffffffffffffffff81116111e6575b60051b0190565b6111ee610af5565b6111df565b9060209182818303126101165780519067ffffffffffffffff82116101165701601f9282848301121561011657815161122b816111cc565b9460409061123b82519788610b7e565b828752838088019360071b86010194868611610116578401925b858410611266575050505050505090565b86828501121561011657825161127b81610b46565b80608086018981116101165791879287949294905b8082106112a857505060809350815201930192611255565b8151865294840194899490910190611290565b9060609173ffffffffffffffffffffffffffffffffffffffff6040820192168152602092816040858094015285518094520193019160005b828110611301575050505090565b8351855293810193928101926001016112f3565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602090805115611353570190565b61135b611315565b0190565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211811515166113c0570290565b6113c861135f565b0290565b81156113d6570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f00000000000000000000000000000000000000000000000000000000000000006114308282612d0f565b939294915094801515600014611847576114a09073ffffffffffffffffffffffffffffffffffffffff8416906114ba61146885612ba2565b604051907fd1741f680000000000000000000000000000000000000000000000000000000082528180600097889333600484016112bb565b0381875afa90811561183a575b8591611818575b50611345565b5180518211156117f6576020915001515b813b156117f2576040517ff242432a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101859052606481019190915260a06084820152600060a48201529190829060c490829084905af180156117e5575b6117d2575b505b73ffffffffffffffffffffffffffffffffffffffff80921692833b1561011657829160405180957f744fb6ca00000000000000000000000000000000000000000000000000000000825260009687918183816115d3886004830160809181527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602082015260606040820152600060608201520190565b03925af180156117c5575b6117b2575b508462010000821161179f575b5050604051947fad5c4648000000000000000000000000000000000000000000000000000000008652856004816020968794165afa948515611792575b8495611773575b5015611766576040517f0dfe1681000000000000000000000000000000000000000000000000000000008152918582168184600481845afa938415611759575b8594611733575b509080600492604051938480927fd21220a70000000000000000000000000000000000000000000000000000000082525afa948515611726575b94611707575b505080841680828416141591826116fa575b5050156116e257505050610e31903390613181565b826116f5916116f5610e31963090613181565b61276b565b84161415905038806116cd565b61171e929450803d106105f1576105e28183610b7e565b9138806116bb565b61172e610bd7565b6116b5565b8291945091611750600493823d84116105f1576105e28183610b7e565b9491925061167b565b611761610bd7565b611674565b915050610e31921661276b565b61178b919550833d85116105f1576105e28183610b7e565b9338611634565b61179a610bd7565b61162d565b6117ab9160101c611405565b38846115f0565b80610a1d6117bf92610b25565b386115e3565b6117cd610bd7565b6115de565b80610a1d6117df92610b25565b3861153a565b6117ed610bd7565b611535565b8280fd5b604061180a6118139360608401519061138f565b910151906113cc565b6114cb565b61183491503d8087833e61182c8183610b7e565b8101906111f3565b386114b4565b611842610bd7565b6114ad565b506040517efdd58e0000000000000000000000000000000000000000000000000000000081523060048201526024810182905260208160448173ffffffffffffffffffffffffffffffffffffffff87165afa9081156118d4575b6000916118b6575b5061153c575b5050505050565b6118ce915060203d8111610570576105618183610b7e565b386118a9565b6118dc610bd7565b6118a1565b51906dffffffffffffffffffffffffffff8216820361011657565b9081606091031261011657611910816118e1565b91604061191f602084016118e1565b92015163ffffffff811681036101165790565b91907f000000000000000000000000000000000000000000000000000000000000000061195f8482612d0f565b91509591936040968796875180937fad5c464800000000000000000000000000000000000000000000000000000000825260209889856004809d819a848873ffffffffffffffffffffffffffffffffffffffff9d8e9d8e8a165afa9788156126c0575b6000986126a1575b50156124fc57898316958151957f0dfe1681000000000000000000000000000000000000000000000000000000008752858785818b5afa9687156124ef575b6000976124d0575b508b8351987fd21220a7000000000000000000000000000000000000000000000000000000008a52878a8781845afa998a156124c3575b60009a612476575b5087948c868b9996611c539f968f9c968f969b6116f59f9c988f99611c289a8f85859e16958681831614600014611f715750505091611ba59381926060611b38958c51948580927f0902f1ac0000000000000000000000000000000000000000000000000000000082525afa918215611f64575b6000938493611f2b575b508b517f70a08231000000000000000000000000000000000000000000000000000000008152309581019586529394849190829081906020015b03915afa918215611f1e575b600092611eff575b506dffffffffffffffffffffffffffff80911692169085612f0e565b86517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384168b820190815260208101929092529583166040820152918716606083015260808201929092528391829160a00190565b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af48015611ef2575b611ed5575b505b517f198d12f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff948516938101938452958416602084015290921660408201528391829160600190565b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af48015611ec8575b611eab575b5061276b565b1692611c5e84612914565b84875180957f70a082310000000000000000000000000000000000000000000000000000000082528180611cb1308c830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa938415611e9e575b600094611e7f575b501691823b15610116576000611d20918751809381927faa0b7db7000000000000000000000000000000000000000000000000000000008352868a840190916080928252602082015260606040820152600060608201520190565b038183875af18015611e72575b611e5f575b5084517efdd58e00000000000000000000000000000000000000000000000000000000815230858201908152602081018390528490829081906040010381865afa938415611e52575b600094611e33575b5050813b156101165760008094611e079651968795869485937ff242432a000000000000000000000000000000000000000000000000000000008552339030908601929060c0949273ffffffffffffffffffffffffffffffffffffffff80921685521660208401526040830152606082015260a06080820152600060a08201520190565b03925af18015611e26575b611e195750565b80610a1d610e3192610b25565b611e2e610bd7565b611e12565b611e4a929450803d10610570576105618183610b7e565b913880611d83565b611e5a610bd7565b611d7b565b80610a1d611e6c92610b25565b38611d32565b611e7a610bd7565b611d2d565b611e97919450853d8711610570576105618183610b7e565b9238611cc5565b611ea6610bd7565b611cbd565b611ec1908d803d10610570576105618183610b7e565b5038611c4d565b611ed0610bd7565b611c48565b611eeb90873d8911610570576105618183610b7e565b5038611bca565b611efa610bd7565b611bc5565b611f17919250883d8a11610570576105618183610b7e565b9038611b1c565b611f26610bd7565b611b14565b611b089450611f5291935060603d8111611f5d575b611f4a8183610b7e565b8101906118fc565b509093909290611ace565b503d611f40565b611f6c610bd7565b611ac4565b92935090918b1685036120fe57505091612007916060612074948a51928380927f0902f1ac0000000000000000000000000000000000000000000000000000000082525afa9081156120f1575b878d60009283946120c9575b508b517f70a08231000000000000000000000000000000000000000000000000000000008152309181019182529394849182908190602001611b08565b86517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384168b820190815260208101929092529583166040820152918c16606083015260808201929092528391829160a00190565b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af480156120bc575b61209f575b50611bcc565b6120b590873d8911610570576105618183610b7e565b5038612099565b6120c4610bd7565b612094565b611b0894506120e791935060603d8111611f5d57611f4a8183610b7e565b5092909293611fca565b6120f9610bd7565b611fbe565b949291509592946122bd9795848a5180927f70a08231000000000000000000000000000000000000000000000000000000008252818061215d3089830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa908115612469575b60009161244c575b5060011c948482612183868a856132eb565b15612386578b517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816878301908152602081018b9052818c166040820152941660608501526080840191909152918290819060a001038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af48015612379575b61235c575b505b61222383878c6132eb565b156122e55788517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841692810192835260208301959095528286166040830152918916606082015260808101919091528290819060a0015b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af480156122d8575b6122c2575061276b565b611bcc565b611ec1908a3d8c11610570576105618183610b7e565b6122e0610bd7565b6122b3565b88517f097693e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416928101928352602083019590955282861660408301528287166060830152918916608082015260a08101919091528290819060c001612293565b61237290853d8711610570576105618183610b7e565b5038612216565b612381610bd7565b612211565b8b517f097693e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816878301908152602081018b9052818c166040820152818d1660608201529416608085015260a0840191909152918290819060c001038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af4801561243f575b612422575b50612218565b61243890853d8711610570576105618183610b7e565b503861241c565b612447610bd7565b612417565b6124639150853d8711610570576105618183610b7e565b38612171565b612471610bd7565b612169565b869a5094889c898b99968a99968f9d96839a8f9e3d86116124bc575b61249c8183610b7e565b81016124a791610bbf565b9f50965096995096999b50509c509497611a50565b503d612492565b6124cb610bd7565b611a48565b6124e8919750863d88116105f1576105e28183610b7e565b9538611a11565b6124f7610bd7565b611a09565b6125f397959492508051947f70a082310000000000000000000000000000000000000000000000000000000086528987898d888a8061255a308b830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03818487165afa998a15612694575b60009a61266d575b50878361257f9286166132eb565b156125f85750612293935197889687967f64eb8ac9000000000000000000000000000000000000000000000000000000008852870191909360809396959460a084019773ffffffffffffffffffffffffffffffffffffffff9384809316865260208601521660408401521660608201520152565b611c53565b93517f097693e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff96871695810195865260208601989098528516604085015291841660608401529216608082015260a08101919091528290819060c001612293565b61257f919a508361268b8a928c8d3d10610570576105618183610b7e565b9b925050612571565b61269c610bd7565b612569565b6126b9919850853d87116105f1576105e28183610b7e565b96386119ca565b6126c8610bd7565b6119c2565b604051906000602083019280841067ffffffffffffffff8511176126f9575b8360405281815292369037565b612701610af5565b6126ec565b1561270d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f51756172747a3a20455448207472616e73666572206661696c656400000000006044820152fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529173ffffffffffffffffffffffffffffffffffffffff8281169291602085602481875afa9485156128a0575b600095612880575b5084156118af57169182036128735750803b15610116576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815260048101929092526000908290602490829084905af18015612866575b612853575b50610e316000804761283a6126cd565b9060208251920190335af161284d610fdc565b50612706565b80610a1d61286092610b25565b3861282a565b61286e610bd7565b612825565b610e3192915033906128ad565b61289991955060203d8111610570576105618183610b7e565b93386127cb565b6128a8610bd7565b6127c3565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff929092166024830152604480830193909352918152610e319161290f606483610b7e565b610ee3565b73ffffffffffffffffffffffffffffffffffffffff908181169081600052600060205260ff604060002054161561294a57505050565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000000000000000000000000000000000000000000009390931673ffffffffffffffffffffffffffffffffffffffff81166024850152610e3193612ac193612a9b92612a6992612a95926129f39190602090829060449082905afa908115612b0a575b600091612aec575b5015612b17565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff90911660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60448201529182906064820190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610b7e565b82610ee3565b73ffffffffffffffffffffffffffffffffffffffff166000526000602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b612b04915060203d8111610570576105618183610b7e565b386129ec565b612b12610bd7565b6129e4565b15612b1e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152fd5b9060405191612bb083610b62565b60018352602083016020368237835115612bc75752565b612bcf611315565b52565b91908260409103126101165760208251612beb81610157565b92015161ffff811681036101165790565b73ffffffffffffffffffffffffffffffffffffffff612c1f60049360209361360f565b16604051928380927ff887ea400000000000000000000000000000000000000000000000000000000082525afa908115612c77575b600091612c5f575090565b610bd4915060203d81116105f1576105e28183610b7e565b612c7f610bd7565b612c54565b15612c8b57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f51756172747a3a2054686973207661756c742063616e6e6f74206265207a617060448201527f70656400000000000000000000000000000000000000000000000000000000006064820152fd5b600091612d1b9161360f565b9073ffffffffffffffffffffffffffffffffffffffff90818316936040517ff887ea4000000000000000000000000000000000000000000000000000000000815260209384826004818a5afa918215612ed6575b600092612eb7575b50806004868499604051928380927fd23e04800000000000000000000000000000000000000000000000000000000082525afa908115612eaa575b600091612e8d575b501694604051927fc45a01550000000000000000000000000000000000000000000000000000000080855282856004818b5afa60009581612e6e575b50612e02575050505050565b839495965083916004849260405194859384928352165afa918215612e61575b600092612e44575b50501691161490612e3a82612c84565b38808080806118af565b612e5a9250803d106105f1576105e28183610b7e565b3880612e2a565b612e69610bd7565b612e22565b612e86919650843d86116105f1576105e28183610b7e565b9438612df6565b612ea49150873d89116105f1576105e28183610b7e565b38612dba565b612eb2610bd7565b612db2565b612ecf919250853d87116105f1576105e28183610b7e565b9038612d77565b612ede610bd7565b612d6f565b81198111612eef570190565b61135b61135f565b818110612f02570390565b612f0a61135f565b0390565b73ffffffffffffffffffffffffffffffffffffffff613031929361302c92610bd4968660011c9384921692604051917f054d50d400000000000000000000000000000000000000000000000000000000835260209482868580612f888684988b600485016040919493926060820195825260208201520152565b0381855afa948515613094575b600095613069575b5084612fb0612ffe9697612fb693612ee3565b93612ef7565b916040518095819482937fad615dec0000000000000000000000000000000000000000000000000000000084528b600485016040919493926060820195825260208201520152565b03915afa92831561305c575b600093613037575b505061302283613027939461138f565b61138f565b6113cc565b6134c5565b90612ef7565b6130279350613022918161305692903d10610570576105618183610b7e565b92613012565b613064610bd7565b61300a565b612ffe955090612fb061308b612fb693873d8911610570576105618183610b7e565b96505090612f9d565b61309c610bd7565b612f95565b9190826040910312610116576020825192015190565b156130be57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f51756172747a3a20494e53554646494349454e545f415f414d4f554e540000006044820152fd5b1561312357565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f51756172747a3a20494e53554646494349454e545f425f414d4f554e540000006044820152fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529173ffffffffffffffffffffffffffffffffffffffff9190911690602083602481855afa9283156132de575b6000936132be575b5082156132b957613250826040926131ff610e3196836000976128ad565b83519485809481937f89afcb440000000000000000000000000000000000000000000000000000000083526004830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03925af180156132ac575b600091829161327c575b506132756103e8809310156130b7565b101561311c565b905061329f915060403d81116132a5575b6132978183610b7e565b8101906130a1565b38613265565b503d61328d565b6132b4610bd7565b61325b565b505050565b6132d791935060203d8111610570576105618183610b7e565b91386131e1565b6132e6610bd7565b6131d9565b6133a790604051927fc45a01550000000000000000000000000000000000000000000000000000000084526020938492838260048173ffffffffffffffffffffffffffffffffffffffff809b165afa9182156134b8575b600092613499575b506040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529216602483015290928391908290879082906044820190565b0392165afa91821561348c575b60009261346f575b5050168015613469576060600491604051928380927f0902f1ac0000000000000000000000000000000000000000000000000000000082525afa90811561345c575b600090819261343a575b506103e890816dffffffffffffffffffffffffffff80921611928361342e575b50505090565b16119050388080613428565b9050613454915060603d8111611f5d57611f4a8183610b7e565b509038613408565b613464610bd7565b6133fe565b50600090565b6134859250803d106105f1576105e28183610b7e565b38806133bc565b613494610bd7565b6133b4565b6134b1919250843d86116105f1576105e28183610b7e565b903861334a565b6134c0610bd7565b613342565b8015613469576001817001000000000000000000000000000000008110156135f8575b61358f61358561357b61357161356761355d6135a097600888680100000000000000006135999a10156135eb575b6401000000008110156135de575b620100008110156135d2575b6101008110156135c6575b60108110156135b9575b10156135b1575b613556818b6113cc565b0160011c90565b613556818a6113cc565b61355681896113cc565b61355681886113cc565b61355681876113cc565b61355681866113cc565b61355681856113cc565b80926113cc565b808210156135ac575090565b905090565b60011b61354c565b60041c9160021b91613545565b811c9160041b9161353b565b60101c91811b91613530565b60201c9160101b91613524565b60401c9160201b91613516565b50680100000000000000009050608082901c6134e8565b81156136c05773ffffffffffffffffffffffffffffffffffffffff91604051907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060208301937fff00000000000000000000000000000000000000000000000000000000000000855260601b16602183015260358201527f577cbdbf32026552c0ae211272febcff3ea352b0c755f8f39b49856dcac710196055820152605581526136b981610b46565b5190201690565b60246040517fafcbb58f00000000000000000000000000000000000000000000000000000000815260006004820152fdfea2646970667358221220e699409d73de0f9e501f90ace3b94af28f03ea82095d3a4f9d975759b15eabf364736f6c634300080e003300000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a7
Deployed Bytecode
0x60806040526004361015610023575b361561001957600080fd5b610021610a61565b005b6000803560e01c9081632201b7ba146100c657508063257d9bb8146100bd5780634f880c4b146100b45780637e2c5c19146100ab578063839006f2146100a2578063a111774d14610099578063f23a6e61146100905763f7bfff2a0361000e5761008b6108e6565b61000e565b5061008b61082b565b5061008b610605565b5061008b610345565b5061008b6102d5565b5061008b610175565b5061008b61011b565b346101085760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261010857610103602435600435611405565b604051f35b80fd5b600091031261011657565b600080fd5b50346101165760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165760206040516103e88152f35b73ffffffffffffffffffffffffffffffffffffffff81160361011657565b50346101165760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576024356101b181610157565b604051907fed63953000000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff90817f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a71660048401526004356024840152166044820152604435606482015260608160848173e932f92d7e09c8742fa2e5293d9ff92364c053f55af480156102c8575b60009081928291610292575b5060408051928352602083019390935273ffffffffffffffffffffffffffffffffffffffff1691810191909152606090f35b0390f35b905061028e92506102ba915060603d81116102c1575b6102b28183610b7e565b810190610be4565b909261025c565b503d6102a8565b6102d0610bd7565b610250565b50346101165760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261011657602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a7168152f35b5034610116576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576000906004359061038682610157565b6104fd816040938451907fe8da52b000000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff908383600481857f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a7165afa9283156105f8575b88936105c9575b5086805180947f29c23e4a00000000000000000000000000000000000000000000000000000000825281858161044060048201906000602083019252565b0392165afa9283156105bc575b889361058c575b5081831615610584575b86517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152929116908383602481855afa928315610577575b8893610548575b508787518096819582947fa9059cbb000000000000000000000000000000000000000000000000000000008452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801561053b575b61051157505051f35b8161053092903d10610534575b6105288183610b7e565b810190610e40565b5051f35b503d61051e565b610543610bd7565b610508565b610569919350843d8611610570575b6105618183610b7e565b810190610c05565b91386104a4565b503d610557565b61057f610bd7565b61049d565b33925061045e565b6105ad919350873d89116105b5575b6105a58183610b7e565b810190612bd2565b509138610454565b503d61059b565b6105c4610bd7565b61044d565b6105ea919350843d86116105f1575b6105e28183610b7e565b810190610bbf565b9138610402565b503d6105d8565b610600610bd7565b6103fb565b50346101165760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165761002160443561064481610157565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152336004820152306024820152610779906064359060209073ffffffffffffffffffffffffffffffffffffffff8516908281604481855afa90811561081e575b600091610801575b506040517f70a0823100000000000000000000000000000000000000000000000000000000808252336004830152948482602481875afa9182156107f4575b6000926107d5575b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81036107b55750839190808210156107ae57505b935b61073e6103e8861015610a6a565b61074a8530338a610db5565b60405190815230600482015291829060249082905afa9182156107a1575b600092610784575b50501015610d2a565b602435600435611932565b61079a9250803d10610570576105618183610b7e565b3880610770565b6107a9610bd7565b610768565b905061072e565b9490856107d0916107c98288961015610c14565b1015610c9f565b610730565b6107ed919250853d8711610570576105618183610b7e565b90386106f8565b6107fc610bd7565b6106f0565b6108189150833d8511610570576105618183610b7e565b386106b1565b610826610bd7565b6106a9565b50346101165760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101165760043561086781610157565b610872602435610157565b60843567ffffffffffffffff80821161011657366023830112156101165781600401359081116101165736910160240111610116576108b361028e91611107565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610116576004356109226103e8341015610a6a565b73ffffffffffffffffffffffffffffffffffffffff60046020610981610968857f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a7612bfc565b73ffffffffffffffffffffffffffffffffffffffff1690565b604051928380927fad5c46480000000000000000000000000000000000000000000000000000000082525afa908115610a54575b600091610a36575b5016803b1561011657610021916040517fd0e30db000000000000000000000000000000000000000000000000000000000815260008160048134875af18015610a29575b610a10575b5060243590611932565b80610a1d610a2392610b25565b8061010b565b38610a06565b610a31610bd7565b610a01565b610a4e915060203d81116105f1576105e28183610b7e565b386109bd565b610a5c610bd7565b6109b5565b333b1561011657565b15610a7157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f51756172747a3a20496e7369676e69666963616e7420696e70757420616d6f7560448201527f6e740000000000000000000000000000000000000000000000000000000000006064820152fd5b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111610b3957604052565b610b41610af5565b604052565b6080810190811067ffffffffffffffff821117610b3957604052565b6040810190811067ffffffffffffffff821117610b3957604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b3957604052565b908160209103126101165751610bd481610157565b90565b506040513d6000823e3d90fd5b908160609103126101165780519160406020830151920151610bd481610157565b90816020910312610116575190565b15610c1b57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f51756172747a3a20496e70757420746f6b656e206973206e6f7420617070726f60448201527f76656400000000000000000000000000000000000000000000000000000000006064820152fd5b15610ca657565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f51756172747a3a20496e70757420746f6b656e2068617320696e73756666696360448201527f69656e742062616c616e636500000000000000000000000000000000000000006064820152fd5b15610d3157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603860248201527f51756172747a3a204665652d6f6e2d7472616e736665722f7265666c6563742060448201527f746f6b656e73206e6f742079657420737570706f7274656400000000000000006064820152fd5b9092610e3193604051937f23b872dd00000000000000000000000000000000000000000000000000000000602086015273ffffffffffffffffffffffffffffffffffffffff809216602486015216604484015260648301526064825260a0820182811067ffffffffffffffff821117610e33575b604052610ee3565b565b610e3b610af5565b610e29565b90816020910312610116575180151581036101165790565b15610e5f57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff169060405190610f0782610b62565b6020928383527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656484840152803b15610f7e5760008281928287610f599796519301915af1610f53610fdc565b90611048565b80519081610f6657505050565b82610e3193610f79938301019101610e40565b610e58565b606484604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b3d15611043573d9067ffffffffffffffff8211611036575b6040519161102a60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610b7e565b82523d6000602084013e565b61103e610af5565b610ff4565b606090565b90919015611054575090565b8151156110645750805190602001fd5b604051907f08c379a00000000000000000000000000000000000000000000000000000000082528160208060048301528251928360248401526000915b8483106110ee575050601f836044947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093116110e1575b01168101030190fd5b60008582860101526110d8565b81830181015186840160440152859350918201916110a1565b73ffffffffffffffffffffffffffffffffffffffff30911603611148577ff23a6e610000000000000000000000000000000000000000000000000000000090565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f51756172747a3a20496d70726f7065722045524331313535207472616e73666560448201527f72000000000000000000000000000000000000000000000000000000000000006064820152fd5b60209067ffffffffffffffff81116111e6575b60051b0190565b6111ee610af5565b6111df565b9060209182818303126101165780519067ffffffffffffffff82116101165701601f9282848301121561011657815161122b816111cc565b9460409061123b82519788610b7e565b828752838088019360071b86010194868611610116578401925b858410611266575050505050505090565b86828501121561011657825161127b81610b46565b80608086018981116101165791879287949294905b8082106112a857505060809350815201930192611255565b8151865294840194899490910190611290565b9060609173ffffffffffffffffffffffffffffffffffffffff6040820192168152602092816040858094015285518094520193019160005b828110611301575050505090565b8351855293810193928101926001016112f3565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602090805115611353570190565b61135b611315565b0190565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211811515166113c0570290565b6113c861135f565b0290565b81156113d6570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a76114308282612d0f565b939294915094801515600014611847576114a09073ffffffffffffffffffffffffffffffffffffffff8416906114ba61146885612ba2565b604051907fd1741f680000000000000000000000000000000000000000000000000000000082528180600097889333600484016112bb565b0381875afa90811561183a575b8591611818575b50611345565b5180518211156117f6576020915001515b813b156117f2576040517ff242432a00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101859052606481019190915260a06084820152600060a48201529190829060c490829084905af180156117e5575b6117d2575b505b73ffffffffffffffffffffffffffffffffffffffff80921692833b1561011657829160405180957f744fb6ca00000000000000000000000000000000000000000000000000000000825260009687918183816115d3886004830160809181527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602082015260606040820152600060608201520190565b03925af180156117c5575b6117b2575b508462010000821161179f575b5050604051947fad5c4648000000000000000000000000000000000000000000000000000000008652856004816020968794165afa948515611792575b8495611773575b5015611766576040517f0dfe1681000000000000000000000000000000000000000000000000000000008152918582168184600481845afa938415611759575b8594611733575b509080600492604051938480927fd21220a70000000000000000000000000000000000000000000000000000000082525afa948515611726575b94611707575b505080841680828416141591826116fa575b5050156116e257505050610e31903390613181565b826116f5916116f5610e31963090613181565b61276b565b84161415905038806116cd565b61171e929450803d106105f1576105e28183610b7e565b9138806116bb565b61172e610bd7565b6116b5565b8291945091611750600493823d84116105f1576105e28183610b7e565b9491925061167b565b611761610bd7565b611674565b915050610e31921661276b565b61178b919550833d85116105f1576105e28183610b7e565b9338611634565b61179a610bd7565b61162d565b6117ab9160101c611405565b38846115f0565b80610a1d6117bf92610b25565b386115e3565b6117cd610bd7565b6115de565b80610a1d6117df92610b25565b3861153a565b6117ed610bd7565b611535565b8280fd5b604061180a6118139360608401519061138f565b910151906113cc565b6114cb565b61183491503d8087833e61182c8183610b7e565b8101906111f3565b386114b4565b611842610bd7565b6114ad565b506040517efdd58e0000000000000000000000000000000000000000000000000000000081523060048201526024810182905260208160448173ffffffffffffffffffffffffffffffffffffffff87165afa9081156118d4575b6000916118b6575b5061153c575b5050505050565b6118ce915060203d8111610570576105618183610b7e565b386118a9565b6118dc610bd7565b6118a1565b51906dffffffffffffffffffffffffffff8216820361011657565b9081606091031261011657611910816118e1565b91604061191f602084016118e1565b92015163ffffffff811681036101165790565b91907f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a761195f8482612d0f565b91509591936040968796875180937fad5c464800000000000000000000000000000000000000000000000000000000825260209889856004809d819a848873ffffffffffffffffffffffffffffffffffffffff9d8e9d8e8a165afa9788156126c0575b6000986126a1575b50156124fc57898316958151957f0dfe1681000000000000000000000000000000000000000000000000000000008752858785818b5afa9687156124ef575b6000976124d0575b508b8351987fd21220a7000000000000000000000000000000000000000000000000000000008a52878a8781845afa998a156124c3575b60009a612476575b5087948c868b9996611c539f968f9c968f969b6116f59f9c988f99611c289a8f85859e16958681831614600014611f715750505091611ba59381926060611b38958c51948580927f0902f1ac0000000000000000000000000000000000000000000000000000000082525afa918215611f64575b6000938493611f2b575b508b517f70a08231000000000000000000000000000000000000000000000000000000008152309581019586529394849190829081906020015b03915afa918215611f1e575b600092611eff575b506dffffffffffffffffffffffffffff80911692169085612f0e565b86517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384168b820190815260208101929092529583166040820152918716606083015260808201929092528391829160a00190565b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af48015611ef2575b611ed5575b505b517f198d12f200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff948516938101938452958416602084015290921660408201528391829160600190565b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af48015611ec8575b611eab575b5061276b565b1692611c5e84612914565b84875180957f70a082310000000000000000000000000000000000000000000000000000000082528180611cb1308c830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa938415611e9e575b600094611e7f575b501691823b15610116576000611d20918751809381927faa0b7db7000000000000000000000000000000000000000000000000000000008352868a840190916080928252602082015260606040820152600060608201520190565b038183875af18015611e72575b611e5f575b5084517efdd58e00000000000000000000000000000000000000000000000000000000815230858201908152602081018390528490829081906040010381865afa938415611e52575b600094611e33575b5050813b156101165760008094611e079651968795869485937ff242432a000000000000000000000000000000000000000000000000000000008552339030908601929060c0949273ffffffffffffffffffffffffffffffffffffffff80921685521660208401526040830152606082015260a06080820152600060a08201520190565b03925af18015611e26575b611e195750565b80610a1d610e3192610b25565b611e2e610bd7565b611e12565b611e4a929450803d10610570576105618183610b7e565b913880611d83565b611e5a610bd7565b611d7b565b80610a1d611e6c92610b25565b38611d32565b611e7a610bd7565b611d2d565b611e97919450853d8711610570576105618183610b7e565b9238611cc5565b611ea6610bd7565b611cbd565b611ec1908d803d10610570576105618183610b7e565b5038611c4d565b611ed0610bd7565b611c48565b611eeb90873d8911610570576105618183610b7e565b5038611bca565b611efa610bd7565b611bc5565b611f17919250883d8a11610570576105618183610b7e565b9038611b1c565b611f26610bd7565b611b14565b611b089450611f5291935060603d8111611f5d575b611f4a8183610b7e565b8101906118fc565b509093909290611ace565b503d611f40565b611f6c610bd7565b611ac4565b92935090918b1685036120fe57505091612007916060612074948a51928380927f0902f1ac0000000000000000000000000000000000000000000000000000000082525afa9081156120f1575b878d60009283946120c9575b508b517f70a08231000000000000000000000000000000000000000000000000000000008152309181019182529394849182908190602001611b08565b86517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9384168b820190815260208101929092529583166040820152918c16606083015260808201929092528391829160a00190565b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af480156120bc575b61209f575b50611bcc565b6120b590873d8911610570576105618183610b7e565b5038612099565b6120c4610bd7565b612094565b611b0894506120e791935060603d8111611f5d57611f4a8183610b7e565b5092909293611fca565b6120f9610bd7565b611fbe565b949291509592946122bd9795848a5180927f70a08231000000000000000000000000000000000000000000000000000000008252818061215d3089830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03915afa908115612469575b60009161244c575b5060011c948482612183868a856132eb565b15612386578b517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816878301908152602081018b9052818c166040820152941660608501526080840191909152918290819060a001038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af48015612379575b61235c575b505b61222383878c6132eb565b156122e55788517f64eb8ac900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff93841692810192835260208301959095528286166040830152918916606082015260808101919091528290819060a0015b038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af480156122d8575b6122c2575061276b565b611bcc565b611ec1908a3d8c11610570576105618183610b7e565b6122e0610bd7565b6122b3565b88517f097693e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff938416928101928352602083019590955282861660408301528287166060830152918916608082015260a08101919091528290819060c001612293565b61237290853d8711610570576105618183610b7e565b5038612216565b612381610bd7565b612211565b8b517f097693e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816878301908152602081018b9052818c166040820152818d1660608201529416608085015260a0840191909152918290819060c001038173e932f92d7e09c8742fa2e5293d9ff92364c053f55af4801561243f575b612422575b50612218565b61243890853d8711610570576105618183610b7e565b503861241c565b612447610bd7565b612417565b6124639150853d8711610570576105618183610b7e565b38612171565b612471610bd7565b612169565b869a5094889c898b99968a99968f9d96839a8f9e3d86116124bc575b61249c8183610b7e565b81016124a791610bbf565b9f50965096995096999b50509c509497611a50565b503d612492565b6124cb610bd7565b611a48565b6124e8919750863d88116105f1576105e28183610b7e565b9538611a11565b6124f7610bd7565b611a09565b6125f397959492508051947f70a082310000000000000000000000000000000000000000000000000000000086528987898d888a8061255a308b830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03818487165afa998a15612694575b60009a61266d575b50878361257f9286166132eb565b156125f85750612293935197889687967f64eb8ac9000000000000000000000000000000000000000000000000000000008852870191909360809396959460a084019773ffffffffffffffffffffffffffffffffffffffff9384809316865260208601521660408401521660608201520152565b611c53565b93517f097693e600000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff96871695810195865260208601989098528516604085015291841660608401529216608082015260a08101919091528290819060c001612293565b61257f919a508361268b8a928c8d3d10610570576105618183610b7e565b9b925050612571565b61269c610bd7565b612569565b6126b9919850853d87116105f1576105e28183610b7e565b96386119ca565b6126c8610bd7565b6119c2565b604051906000602083019280841067ffffffffffffffff8511176126f9575b8360405281815292369037565b612701610af5565b6126ec565b1561270d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f51756172747a3a20455448207472616e73666572206661696c656400000000006044820152fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529173ffffffffffffffffffffffffffffffffffffffff8281169291602085602481875afa9485156128a0575b600095612880575b5084156118af57169182036128735750803b15610116576040517f2e1a7d4d00000000000000000000000000000000000000000000000000000000815260048101929092526000908290602490829084905af18015612866575b612853575b50610e316000804761283a6126cd565b9060208251920190335af161284d610fdc565b50612706565b80610a1d61286092610b25565b3861282a565b61286e610bd7565b612825565b610e3192915033906128ad565b61289991955060203d8111610570576105618183610b7e565b93386127cb565b6128a8610bd7565b6127c3565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff929092166024830152604480830193909352918152610e319161290f606483610b7e565b610ee3565b73ffffffffffffffffffffffffffffffffffffffff908181169081600052600060205260ff604060002054161561294a57505050565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a79390931673ffffffffffffffffffffffffffffffffffffffff81166024850152610e3193612ac193612a9b92612a6992612a95926129f39190602090829060449082905afa908115612b0a575b600091612aec575b5015612b17565b6040517f095ea7b300000000000000000000000000000000000000000000000000000000602082015273ffffffffffffffffffffffffffffffffffffffff90911660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60448201529182906064820190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610b7e565b82610ee3565b73ffffffffffffffffffffffffffffffffffffffff166000526000602052604060002090565b60017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055565b612b04915060203d8111610570576105618183610b7e565b386129ec565b612b12610bd7565b6129e4565b15612b1e57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152fd5b9060405191612bb083610b62565b60018352602083016020368237835115612bc75752565b612bcf611315565b52565b91908260409103126101165760208251612beb81610157565b92015161ffff811681036101165790565b73ffffffffffffffffffffffffffffffffffffffff612c1f60049360209361360f565b16604051928380927ff887ea400000000000000000000000000000000000000000000000000000000082525afa908115612c77575b600091612c5f575090565b610bd4915060203d81116105f1576105e28183610b7e565b612c7f610bd7565b612c54565b15612c8b57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f51756172747a3a2054686973207661756c742063616e6e6f74206265207a617060448201527f70656400000000000000000000000000000000000000000000000000000000006064820152fd5b600091612d1b9161360f565b9073ffffffffffffffffffffffffffffffffffffffff90818316936040517ff887ea4000000000000000000000000000000000000000000000000000000000815260209384826004818a5afa918215612ed6575b600092612eb7575b50806004868499604051928380927fd23e04800000000000000000000000000000000000000000000000000000000082525afa908115612eaa575b600091612e8d575b501694604051927fc45a01550000000000000000000000000000000000000000000000000000000080855282856004818b5afa60009581612e6e575b50612e02575050505050565b839495965083916004849260405194859384928352165afa918215612e61575b600092612e44575b50501691161490612e3a82612c84565b38808080806118af565b612e5a9250803d106105f1576105e28183610b7e565b3880612e2a565b612e69610bd7565b612e22565b612e86919650843d86116105f1576105e28183610b7e565b9438612df6565b612ea49150873d89116105f1576105e28183610b7e565b38612dba565b612eb2610bd7565b612db2565b612ecf919250853d87116105f1576105e28183610b7e565b9038612d77565b612ede610bd7565b612d6f565b81198111612eef570190565b61135b61135f565b818110612f02570390565b612f0a61135f565b0390565b73ffffffffffffffffffffffffffffffffffffffff613031929361302c92610bd4968660011c9384921692604051917f054d50d400000000000000000000000000000000000000000000000000000000835260209482868580612f888684988b600485016040919493926060820195825260208201520152565b0381855afa948515613094575b600095613069575b5084612fb0612ffe9697612fb693612ee3565b93612ef7565b916040518095819482937fad615dec0000000000000000000000000000000000000000000000000000000084528b600485016040919493926060820195825260208201520152565b03915afa92831561305c575b600093613037575b505061302283613027939461138f565b61138f565b6113cc565b6134c5565b90612ef7565b6130279350613022918161305692903d10610570576105618183610b7e565b92613012565b613064610bd7565b61300a565b612ffe955090612fb061308b612fb693873d8911610570576105618183610b7e565b96505090612f9d565b61309c610bd7565b612f95565b9190826040910312610116576020825192015190565b156130be57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f51756172747a3a20494e53554646494349454e545f415f414d4f554e540000006044820152fd5b1561312357565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f51756172747a3a20494e53554646494349454e545f425f414d4f554e540000006044820152fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529173ffffffffffffffffffffffffffffffffffffffff9190911690602083602481855afa9283156132de575b6000936132be575b5082156132b957613250826040926131ff610e3196836000976128ad565b83519485809481937f89afcb440000000000000000000000000000000000000000000000000000000083526004830191909173ffffffffffffffffffffffffffffffffffffffff6020820193169052565b03925af180156132ac575b600091829161327c575b506132756103e8809310156130b7565b101561311c565b905061329f915060403d81116132a5575b6132978183610b7e565b8101906130a1565b38613265565b503d61328d565b6132b4610bd7565b61325b565b505050565b6132d791935060203d8111610570576105618183610b7e565b91386131e1565b6132e6610bd7565b6131d9565b6133a790604051927fc45a01550000000000000000000000000000000000000000000000000000000084526020938492838260048173ffffffffffffffffffffffffffffffffffffffff809b165afa9182156134b8575b600092613499575b506040517fe6a4390500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201529216602483015290928391908290879082906044820190565b0392165afa91821561348c575b60009261346f575b5050168015613469576060600491604051928380927f0902f1ac0000000000000000000000000000000000000000000000000000000082525afa90811561345c575b600090819261343a575b506103e890816dffffffffffffffffffffffffffff80921611928361342e575b50505090565b16119050388080613428565b9050613454915060603d8111611f5d57611f4a8183610b7e565b509038613408565b613464610bd7565b6133fe565b50600090565b6134859250803d106105f1576105e28183610b7e565b38806133bc565b613494610bd7565b6133b4565b6134b1919250843d86116105f1576105e28183610b7e565b903861334a565b6134c0610bd7565b613342565b8015613469576001817001000000000000000000000000000000008110156135f8575b61358f61358561357b61357161356761355d6135a097600888680100000000000000006135999a10156135eb575b6401000000008110156135de575b620100008110156135d2575b6101008110156135c6575b60108110156135b9575b10156135b1575b613556818b6113cc565b0160011c90565b613556818a6113cc565b61355681896113cc565b61355681886113cc565b61355681876113cc565b61355681866113cc565b61355681856113cc565b80926113cc565b808210156135ac575090565b905090565b60011b61354c565b60041c9160021b91613545565b811c9160041b9161353b565b60101c91811b91613530565b60201c9160101b91613524565b60401c9160201b91613516565b50680100000000000000009050608082901c6134e8565b81156136c05773ffffffffffffffffffffffffffffffffffffffff91604051907fffffffffffffffffffffffffffffffffffffffff00000000000000000000000060208301937fff00000000000000000000000000000000000000000000000000000000000000855260601b16602183015260358201527f577cbdbf32026552c0ae211272febcff3ea352b0c755f8f39b49856dcac710196055820152605581526136b981610b46565b5190201690565b60246040517fafcbb58f00000000000000000000000000000000000000000000000000000000815260006004820152fdfea2646970667358221220e699409d73de0f9e501f90ace3b94af28f03ea82095d3a4f9d975759b15eabf364736f6c634300080e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a7
-----Decoded View---------------
Arg [0] : _vaultHealer (address): 0x14E1BC2Da67dE9e9eFd7116d9D2f6801374c32a7
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000014e1bc2da67de9e9efd7116d9d2f6801374c32a7
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.