More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 600 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Partial Withdraw | 19993777 | 49 days ago | IN | 0 ETH | 0.00059094 | ||||
Partial Withdraw | 19828705 | 72 days ago | IN | 0 ETH | 0.00041494 | ||||
Withdraw | 19825129 | 72 days ago | IN | 0 ETH | 0.00041253 | ||||
Partial Withdraw | 19825117 | 72 days ago | IN | 0 ETH | 0.000466 | ||||
Withdraw | 19825105 | 72 days ago | IN | 0 ETH | 0.0005107 | ||||
Partial Withdraw | 19499970 | 118 days ago | IN | 0 ETH | 0.01486438 | ||||
Partial Withdraw | 19493791 | 119 days ago | IN | 0 ETH | 0.00552082 | ||||
Claim Yield | 19251514 | 153 days ago | IN | 0 ETH | 0.00677899 | ||||
Partial Withdraw | 18847570 | 209 days ago | IN | 0 ETH | 0.00654936 | ||||
Partial Withdraw | 18757174 | 222 days ago | IN | 0 ETH | 0.01166837 | ||||
Partial Withdraw | 18669574 | 234 days ago | IN | 0 ETH | 0.00350681 | ||||
Claim Yield | 18648002 | 237 days ago | IN | 0 ETH | 0.00353397 | ||||
Partial Withdraw | 18591925 | 245 days ago | IN | 0 ETH | 0.01036742 | ||||
Claim Yield | 18591918 | 245 days ago | IN | 0 ETH | 0.00328637 | ||||
Partial Withdraw | 18583325 | 246 days ago | IN | 0 ETH | 0.00312107 | ||||
Withdraw | 18579975 | 247 days ago | IN | 0 ETH | 0.01783199 | ||||
Partial Withdraw | 18579680 | 247 days ago | IN | 0 ETH | 0.00843284 | ||||
Claim Yield | 18406434 | 271 days ago | IN | 0 ETH | 0.0008935 | ||||
Partial Withdraw | 18406429 | 271 days ago | IN | 0 ETH | 0.00101903 | ||||
Partial Withdraw | 18406376 | 271 days ago | IN | 0 ETH | 0.00117658 | ||||
Partial Withdraw | 18234597 | 295 days ago | IN | 0 ETH | 0.00179405 | ||||
Partial Withdraw | 18099564 | 314 days ago | IN | 0 ETH | 0.00207887 | ||||
Partial Withdraw | 18072051 | 318 days ago | IN | 0 ETH | 0.0039457 | ||||
Partial Withdraw | 18072044 | 318 days ago | IN | 0 ETH | 0.00380979 | ||||
Claim Yield | 18071122 | 318 days ago | IN | 0 ETH | 0.00268303 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Vault
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol"; import {Counters} from "@openzeppelin/contracts/utils/Counters.sol"; import {IVault} from "./vault/IVault.sol"; import {IVaultSponsoring} from "./vault/IVaultSponsoring.sol"; import {IVaultSettings} from "./vault/IVaultSettings.sol"; import {CurveSwapper} from "./vault/CurveSwapper.sol"; import {PercentMath} from "./lib/PercentMath.sol"; import {ExitPausable} from "./lib/ExitPausable.sol"; import {IStrategy} from "./strategy/IStrategy.sol"; import {CustomErrors} from "./interfaces/CustomErrors.sol"; /** * A vault where other accounts can deposit an underlying token * currency and set distribution params for their principal and yield * * @notice The underlying token can be automatically swapped from any configured ERC20 token via {CurveSwapper} */ contract Vault is IVault, IVaultSponsoring, IVaultSettings, CurveSwapper, Context, ERC165, AccessControl, ReentrancyGuard, Pausable, ExitPausable, CustomErrors { using SafeERC20 for IERC20; using SafeERC20 for IERC20Metadata; using PercentMath for uint256; using PercentMath for uint16; using Counters for Counters.Counter; // // Constants // /// Role allowed to invest/desinvest from strategy bytes32 public constant KEEPER_ROLE = keccak256("KEEPER_ROLE"); /// Role allowed to change settings such as performance fee and investment fee bytes32 public constant SETTINGS_ROLE = keccak256("SETTINGS_ROLE"); /// Role for sponsors allowed to call sponsor/unsponsor bytes32 public constant SPONSOR_ROLE = keccak256("SPONSOR_ROLE"); /// Minimum lock for each sponsor uint64 public constant MIN_SPONSOR_LOCK_DURATION = 2 weeks; /// Maximum lock for each sponsor uint64 public constant MAX_SPONSOR_LOCK_DURATION = 24 weeks; /// Maximum lock for each deposit uint64 public constant MAX_DEPOSIT_LOCK_DURATION = 24 weeks; /// Helper constant for computing shares without losing precision uint256 public constant SHARES_MULTIPLIER = 1e18; // // State // /// @inheritdoc IVault IERC20Metadata public override(IVault) underlying; /// @inheritdoc IVault uint16 public override(IVault) investPct; /// @inheritdoc IVault uint64 public immutable override(IVault) minLockPeriod; /// @inheritdoc IVaultSponsoring uint256 public override(IVaultSponsoring) totalSponsored; /// @inheritdoc IVault uint256 public override(IVault) totalShares; /// The investment strategy IStrategy public strategy; /// Unique IDs to correlate donations that belong to the same foundation uint256 private _depositGroupIds; mapping(uint256 => address) public depositGroupIdOwner; /// deposit ID => deposit data mapping(uint256 => Deposit) public deposits; /// Counter for deposit ids Counters.Counter private _depositTokenIds; /// claimer address => claimer data mapping(address => Claimer) public claimer; /// The total of principal deposited uint256 public totalPrincipal; /// Treasury address to collect performance fee address public treasury; /// Performance fee percentage uint16 public perfFeePct; /// Current accumulated performance fee; uint256 public accumulatedPerfFee; /// Loss tolerance pct uint16 public lossTolerancePct; /// Rebalance minimum uint256 private immutable rebalanceMinimum; /** * @param _underlying Underlying ERC20 token to use. * @param _minLockPeriod Minimum lock period to deposit * @param _investPct Percentage of the total underlying to invest in the strategy * @param _treasury Treasury address to collect performance fee * @param _admin Vault admin address * @param _perfFeePct Performance fee percentage * @param _lossTolerancePct Loss tolerance when investing through the strategy * @param _swapPools Swap pools used to automatically convert tokens to underlying */ constructor( IERC20Metadata _underlying, uint64 _minLockPeriod, uint16 _investPct, address _treasury, address _admin, uint16 _perfFeePct, uint16 _lossTolerancePct, SwapPoolParam[] memory _swapPools ) { if (!_investPct.validPct()) revert VaultInvalidInvestpct(); if (!_perfFeePct.validPct()) revert VaultInvalidPerformanceFee(); if (!_lossTolerancePct.validPct()) revert VaultInvalidLossTolerance(); if (address(_underlying) == address(0x0)) revert VaultUnderlyingCannotBe0Address(); if (_treasury == address(0x0)) revert VaultTreasuryCannotBe0Address(); if (_admin == address(0x0)) revert VaultAdminCannotBe0Address(); if (_minLockPeriod == 0 || _minLockPeriod > MAX_DEPOSIT_LOCK_DURATION) revert VaultInvalidMinLockPeriod(); _grantRole(DEFAULT_ADMIN_ROLE, _admin); _grantRole(KEEPER_ROLE, _admin); _grantRole(SETTINGS_ROLE, _admin); _grantRole(SPONSOR_ROLE, _admin); investPct = _investPct; underlying = _underlying; treasury = _treasury; minLockPeriod = _minLockPeriod; perfFeePct = _perfFeePct; lossTolerancePct = _lossTolerancePct; rebalanceMinimum = 10 * 10**underlying.decimals(); _addPools(_swapPools); emit TreasuryUpdated(_treasury); } // // Modifiers // modifier onlyAdmin() { if (!hasRole(DEFAULT_ADMIN_ROLE, msg.sender)) revert VaultCallerNotAdmin(); _; } modifier onlySettings() { if (!hasRole(SETTINGS_ROLE, msg.sender)) revert VaultCallerNotSettings(); _; } modifier onlyKeeper() { if (!hasRole(KEEPER_ROLE, msg.sender)) revert VaultCallerNotKeeper(); _; } modifier onlySponsor() { if (!hasRole(SPONSOR_ROLE, msg.sender)) revert VaultCallerNotSponsor(); _; } /** * Transfers administrator rights for the Vault to another account, * revoking all current admin's roles and setting up the roles for the new admin. * * @notice Can only be called by the admin. * * @param _newAdmin The new admin account. */ function transferAdminRights(address _newAdmin) external onlyAdmin { if (_newAdmin == address(0x0)) revert VaultAdminCannotBe0Address(); if (_newAdmin == msg.sender) revert VaultCannotTransferAdminRightsToSelf(); _grantRole(DEFAULT_ADMIN_ROLE, _newAdmin); _grantRole(KEEPER_ROLE, _newAdmin); _grantRole(SETTINGS_ROLE, _newAdmin); _grantRole(SPONSOR_ROLE, _newAdmin); _revokeRole(DEFAULT_ADMIN_ROLE, msg.sender); _revokeRole(KEEPER_ROLE, msg.sender); _revokeRole(SETTINGS_ROLE, msg.sender); _revokeRole(SPONSOR_ROLE, msg.sender); } // // IVault // /// @inheritdoc IVault function totalUnderlying() public view override(IVault) returns (uint256) { if (address(strategy) != address(0)) { return underlying.balanceOf(address(this)) + strategy.investedAssets(); } return underlying.balanceOf(address(this)); } /// @inheritdoc IVault function yieldFor(address _to) public view override(IVault) returns ( uint256 claimableYield, uint256 shares, uint256 perfFee ) { uint256 claimerPrincipal = claimer[_to].totalPrincipal; uint256 claimerShares = claimer[_to].totalShares; uint256 _totalUnderlyingMinusSponsored = totalUnderlyingMinusSponsored(); uint256 currentClaimerPrincipal = _computeAmount( claimerShares, totalShares, _totalUnderlyingMinusSponsored ); if (currentClaimerPrincipal <= claimerPrincipal) { return (0, 0, 0); } uint256 yieldWithPerfFee = currentClaimerPrincipal - claimerPrincipal; shares = _computeShares( yieldWithPerfFee, totalShares, _totalUnderlyingMinusSponsored ); uint256 sharesAmount = _computeAmount( shares, totalShares, _totalUnderlyingMinusSponsored ); perfFee = sharesAmount.pctOf(perfFeePct); claimableYield = sharesAmount - perfFee; } /// @inheritdoc IVault function depositForGroupId(uint256 _groupId, DepositParams calldata _params) external nonReentrant whenNotPaused returns (uint256[] memory depositIds) { if (depositGroupIdOwner[_groupId] != msg.sender) revert VaultSenderNotOwnerOfGroupId(); depositIds = _doDeposit(_groupId, _params); } /// @inheritdoc IVault function deposit(DepositParams calldata _params) external nonReentrant whenNotPaused returns (uint256[] memory depositIds) { uint256 depositGroupId = _depositGroupIds; _depositGroupIds = depositGroupId + 1; depositGroupIdOwner[depositGroupId] = msg.sender; depositIds = _doDeposit(depositGroupId, _params); } function _doDeposit(uint256 _groupId, DepositParams calldata _params) internal returns (uint256[] memory depositIds) { if (_params.amount == 0) revert VaultCannotDeposit0(); if ( _params.lockDuration < minLockPeriod || _params.lockDuration > MAX_DEPOSIT_LOCK_DURATION ) revert VaultInvalidLockPeriod(); if (bytes(_params.name).length < 3) revert VaultDepositNameTooShort(); uint256 principalMinusStrategyFee = _applyLossTolerance(totalPrincipal); uint256 previousTotalUnderlying = totalUnderlyingMinusSponsored(); if (principalMinusStrategyFee > previousTotalUnderlying) revert VaultCannotDepositWhenYieldNegative(); _transferAndCheckInputToken( msg.sender, _params.inputToken, _params.amount ); uint256 newUnderlyingAmount = _swapIntoUnderlying( _params.inputToken, _params.amount, _params.slippage ); uint64 lockedUntil = _params.lockDuration + _blockTimestamp(); depositIds = _createDeposit( previousTotalUnderlying, newUnderlyingAmount, lockedUntil, _params.claims, _params.name, _groupId ); } /// @inheritdoc IVault function claimYield(address _to) external override(IVault) nonReentrant whenNotExitPaused { if (_to == address(0)) revert VaultDestinationCannotBe0Address(); (uint256 yield, uint256 shares, uint256 fee) = yieldFor(msg.sender); if (yield == 0) revert VaultNoYieldToClaim(); uint256 _totalUnderlyingMinusSponsored = totalUnderlyingMinusSponsored(); uint256 _totalShares = totalShares; accumulatedPerfFee += fee; _rebalanceBeforeWithdrawing(yield); underlying.safeTransfer(_to, yield); claimer[msg.sender].totalShares -= shares; totalShares -= shares; emit YieldClaimed( msg.sender, _to, yield, shares, fee, _totalUnderlyingMinusSponsored, _totalShares ); } /// @inheritdoc IVault function withdraw(address _to, uint256[] calldata _ids) external override(IVault) nonReentrant whenNotExitPaused { if (_to == address(0)) revert VaultDestinationCannotBe0Address(); if (totalPrincipal > totalUnderlyingMinusSponsored()) revert VaultCannotWithdrawWhenYieldNegative(); _withdrawAll(_to, _ids, false); } /// @inheritdoc IVault function forceWithdraw(address _to, uint256[] calldata _ids) external nonReentrant whenNotExitPaused { if (_to == address(0)) revert VaultDestinationCannotBe0Address(); _withdrawAll(_to, _ids, true); } function partialWithdraw( address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) external nonReentrant whenNotExitPaused { if (_to == address(0)) revert VaultDestinationCannotBe0Address(); _withdrawPartial(_to, _ids, _amounts); } /// @inheritdoc IVault function investState() public view override(IVault) returns (uint256 maxInvestableAmount, uint256 alreadyInvested) { if (address(strategy) == address(0)) { return (0, 0); } maxInvestableAmount = totalUnderlying().pctOf(investPct); alreadyInvested = strategy.investedAssets(); } /// @inheritdoc IVault function updateInvested() external override(IVault) onlyKeeper { if (address(strategy) == address(0)) revert VaultStrategyNotSet(); (uint256 maxInvestableAmount, uint256 alreadyInvested) = investState(); if (maxInvestableAmount == alreadyInvested) revert VaultNothingToDo(); // disinvest if (alreadyInvested > maxInvestableAmount) { uint256 disinvestAmount = alreadyInvested - maxInvestableAmount; if (disinvestAmount < rebalanceMinimum) revert VaultNotEnoughToRebalance(); strategy.withdrawToVault(disinvestAmount); emit Disinvested(disinvestAmount); return; } // invest uint256 investAmount = maxInvestableAmount - alreadyInvested; if (investAmount < rebalanceMinimum) revert VaultNotEnoughToRebalance(); underlying.safeTransfer(address(strategy), investAmount); strategy.invest(); emit Invested(investAmount); } /// @inheritdoc IVault function withdrawPerformanceFee() external override(IVault) onlyKeeper { uint256 _perfFee = accumulatedPerfFee; if (_perfFee == 0) revert VaultNoPerformanceFee(); accumulatedPerfFee = 0; _rebalanceBeforeWithdrawing(_perfFee); emit FeeWithdrawn(_perfFee); underlying.safeTransfer(treasury, _perfFee); } // // IVaultSponsoring // /// @inheritdoc IVaultSponsoring function sponsor( address _inputToken, uint256 _amount, uint256 _lockDuration, uint256 _slippage ) external override(IVaultSponsoring) nonReentrant onlySponsor whenNotPaused { if (_amount == 0) revert VaultCannotSponsor0(); if ( _lockDuration < MIN_SPONSOR_LOCK_DURATION || _lockDuration > MAX_SPONSOR_LOCK_DURATION ) revert VaultInvalidLockPeriod(); uint256 lockedUntil = _lockDuration + block.timestamp; _depositTokenIds.increment(); uint256 tokenId = _depositTokenIds.current(); _transferAndCheckInputToken(msg.sender, _inputToken, _amount); uint256 underlyingAmount = _swapIntoUnderlying( _inputToken, _amount, _slippage ); deposits[tokenId] = Deposit( underlyingAmount, msg.sender, address(0), lockedUntil ); totalSponsored += underlyingAmount; emit Sponsored(tokenId, underlyingAmount, msg.sender, lockedUntil); } /// @inheritdoc IVaultSponsoring function unsponsor(address _to, uint256[] calldata _ids) external nonReentrant whenNotExitPaused { if (_to == address(0)) revert VaultDestinationCannotBe0Address(); _unsponsor(_to, _ids); } /// @inheritdoc IVaultSponsoring function partialUnsponsor( address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) external nonReentrant whenNotExitPaused { if (_to == address(0)) revert VaultDestinationCannotBe0Address(); _partialUnsponsor(_to, _ids, _amounts); } // // CurveSwapper // /// @inheritdoc CurveSwapper function getUnderlying() public view override(CurveSwapper) returns (address) { return address(underlying); } /// Adds a new curve swap pool from an input token to {underlying} /// /// @param _param Swap pool params function addPool(SwapPoolParam memory _param) external onlyAdmin { _addPool(_param); } /// Removes an existing swap pool, and the ability to deposit the given token as underlying /// /// @param _inputToken the token to remove function removePool(address _inputToken) external onlyAdmin { _removePool(_inputToken); } // // Admin functions // /// @inheritdoc IVaultSettings function setInvestPct(uint16 _investPct) external override(IVaultSettings) onlySettings { if (!PercentMath.validPct(_investPct)) revert VaultInvalidInvestpct(); emit InvestPctUpdated(_investPct); investPct = _investPct; } /// @inheritdoc IVaultSettings function setTreasury(address _treasury) external override(IVaultSettings) onlySettings { if (address(_treasury) == address(0x0)) revert VaultTreasuryCannotBe0Address(); treasury = _treasury; emit TreasuryUpdated(_treasury); } /// @inheritdoc IVaultSettings function setPerfFeePct(uint16 _perfFeePct) external override(IVaultSettings) onlySettings { if (!PercentMath.validPct(_perfFeePct)) revert VaultInvalidPerformanceFee(); perfFeePct = _perfFeePct; emit PerfFeePctUpdated(_perfFeePct); } /// @inheritdoc IVaultSettings function setStrategy(address _strategy) external override(IVaultSettings) onlySettings { if (_strategy == address(0)) revert VaultStrategyNotSet(); if (IStrategy(_strategy).vault() != address(this)) revert VaultInvalidVault(); if (address(strategy) != address(0) && strategy.hasAssets()) revert VaultStrategyHasInvestedFunds(); strategy = IStrategy(_strategy); emit StrategyUpdated(_strategy); } /// @inheritdoc IVaultSettings function setLossTolerancePct(uint16 pct) external override(IVaultSettings) onlySettings { if (!pct.validPct()) revert VaultInvalidLossTolerance(); lossTolerancePct = pct; emit LossTolerancePctUpdated(pct); } // // Public API // /** * Computes the total amount of principal + yield currently controlled by the * vault and the strategy. The principal + yield is the total amount * of underlying that can be claimed or withdrawn, excluding the sponsored amount and performance fee. * * @return Total amount of principal and yield help by the vault (not including sponsored amount and performance fee). */ function totalUnderlyingMinusSponsored() public view returns (uint256) { uint256 _totalUnderlying = totalUnderlying(); uint256 deductAmount = totalSponsored + accumulatedPerfFee; if (deductAmount > _totalUnderlying) { return 0; } return _totalUnderlying - deductAmount; } // // ERC165 // function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, AccessControl) returns (bool) { return interfaceId == type(IVault).interfaceId || interfaceId == type(IVaultSponsoring).interfaceId || super.supportsInterface(interfaceId); } // // Internal API // /** * Withdraws the principal from the deposits with the ids provided in @param _ids and sends it to @param _to. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. * @param _force Boolean to specify if the action should be perfomed when there's loss. */ function _withdrawAll( address _to, uint256[] calldata _ids, bool _force ) internal { uint256 localTotalShares = totalShares; uint256 localTotalPrincipal = totalUnderlyingMinusSponsored(); uint256 amount; uint256 idsLen = _ids.length; for (uint256 i = 0; i < idsLen; ++i) { uint256 depositAmount = deposits[_ids[i]].amount; amount += _withdrawSingle( _ids[i], localTotalShares, localTotalPrincipal, _to, _force, depositAmount ); } _rebalanceBeforeWithdrawing(amount); underlying.safeTransfer(_to, amount); } function _withdrawPartial( address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) internal { uint256 localTotalShares = totalShares; uint256 localTotalPrincipal = totalUnderlyingMinusSponsored(); uint256 amount; uint256 idsLen = _ids.length; for (uint256 i = 0; i < idsLen; ++i) { amount += _withdrawSingle( _ids[i], localTotalShares, localTotalPrincipal, _to, false, _amounts[i] ); } _rebalanceBeforeWithdrawing(amount); underlying.safeTransfer(_to, amount); } /** * Rebalances the vault's funds to cover the transfer of funds from the vault * by disinvesting from the strategy. After the rebalance the vault is left * with a set percentage (100% - invest%) of the total underlying as reserves. * * @notice this will have effect only for sync strategies. * * @param _amount Funds to be transferred from the vault. */ function _rebalanceBeforeWithdrawing(uint256 _amount) internal { uint256 vaultBalance = underlying.balanceOf(address(this)); if (_amount <= vaultBalance) return; if (!strategy.isSync()) revert VaultNotEnoughFunds(); uint256 expectedReserves = (totalUnderlying() - _amount).pctOf( 10000 - investPct ); // we want to withdraw the from the strategy only what is needed // to cover the transfer and leave the vault with the expected reserves uint256 needed = _amount + expectedReserves - vaultBalance; strategy.withdrawToVault(needed); emit Disinvested(needed); } /** * Withdraws the sponsored amount for the deposits with the ids provided * in @param _ids and sends it to @param _to. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. */ function _unsponsor(address _to, uint256[] calldata _ids) internal { uint256 sponsorAmount; uint256 idsLen = _ids.length; for (uint8 i = 0; i < idsLen; ++i) { uint256 tokenId = _ids[i]; uint256 amount = deposits[tokenId].amount; _unsponsorSingle(_to, tokenId, amount); sponsorAmount += amount; } _decreaseTotalSponsoredAndTransfer(_to, sponsorAmount); } /** * Withdraws the specified sponsored amounts @param _amounts for the deposits with the ids provided * in @param _ids and sends it to @param _to. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. * @param _amounts Array with the amounts to withdraw. */ function _partialUnsponsor( address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) internal { uint256 sponsorAmount; uint256 idsLen = _ids.length; for (uint8 i = 0; i < idsLen; ++i) { uint256 depositId = _ids[i]; uint256 amount = _amounts[i]; _unsponsorSingle(_to, depositId, amount); sponsorAmount += amount; } _decreaseTotalSponsoredAndTransfer(_to, sponsorAmount); } /** * Validates conditions for unsponsoring amount @param _amount of the deposit with the id @param _id. * * @param _to Address that will receive the funds. * @param _tokenId Id of the deposit. * @param _amount Amount to be unsponsored/withdrawn. */ function _unsponsorSingle( address _to, uint256 _tokenId, uint256 _amount ) internal { Deposit memory _deposit = deposits[_tokenId]; if (_deposit.owner != msg.sender) revert VaultNotAllowed(); if (_deposit.lockedUntil > block.timestamp) revert VaultAmountLocked(); if (_deposit.claimerId != address(0)) revert VaultNotSponsor(); if (_deposit.amount < _amount) revert VaultCannotWithdrawMoreThanAvailable(); bool isFull = _amount == _deposit.amount; emit Unsponsored(_tokenId, _amount, _to, isFull); if (!isFull) { deposits[_tokenId].amount -= _amount; return; } delete deposits[_tokenId]; } /** * Updates totalSponsored by subtracting the amount @param _amount and performing a transfer to @param _to. * * @param _to Adress that will receive the funds. * @param _amount Amount being unsponsored. */ function _decreaseTotalSponsoredAndTransfer(address _to, uint256 _amount) internal { if (_amount > totalUnderlying()) revert VaultNotEnoughFunds(); totalSponsored -= _amount; _rebalanceBeforeWithdrawing(_amount); underlying.safeTransfer(_to, _amount); } /** * @dev `_createDeposit` declares too many locals * We move some of them to this struct to fix the problem */ struct CreateDepositLocals { uint256 totalShares; uint256 totalUnderlying; uint16 accumulatedPct; uint256 accumulatedAmount; uint256 claimsLen; } /** * Creates a deposit with the given amount of underlying and claim * structure. The deposit is locked until the timestamp specified in @param _lockedUntil. * @notice This function assumes underlying will be transfered elsewhere in * the transaction. * * @notice Underlying must be transfered *after* this function, in order to * correctly calculate shares. * * @notice claims must add up to 100%. * * @param _amount Amount of underlying to consider @param claims claim * @param _lockedUntil Timestamp at which the deposit unlocks * @param claims Claim params * params. */ function _createDeposit( uint256 _previousTotalUnderlying, uint256 _amount, uint64 _lockedUntil, ClaimParams[] calldata claims, string calldata _name, uint256 _groupId ) internal returns (uint256[] memory) { CreateDepositLocals memory locals = CreateDepositLocals({ totalShares: totalShares, totalUnderlying: _previousTotalUnderlying, accumulatedPct: 0, accumulatedAmount: 0, claimsLen: claims.length }); uint256[] memory result = new uint256[](locals.claimsLen); for (uint256 i = 0; i < locals.claimsLen; ++i) { ClaimParams memory data = claims[i]; if (data.pct == 0) revert VaultClaimPercentageCannotBe0(); if (data.beneficiary == address(0)) revert VaultClaimerCannotBe0(); // if it's the last claim, just grab all remaining amount, instead // of relying on percentages uint256 localAmount = i == locals.claimsLen - 1 ? _amount - locals.accumulatedAmount : _amount.pctOf(data.pct); result[i] = _createClaim( _groupId, localAmount, _lockedUntil, data, locals.totalShares, locals.totalUnderlying, _name ); locals.accumulatedPct += data.pct; locals.accumulatedAmount += localAmount; } if (!locals.accumulatedPct.is100Pct()) revert VaultClaimsDontAddUp(); return result; } /** * @dev `_createClaim` declares too many locals * We move some of them to this struct to fix the problem */ struct CreateClaimLocals { uint256 newShares; address claimerId; uint256 tokenId; } function _createClaim( uint256 _depositGroupId, uint256 _amount, uint64 _lockedUntil, ClaimParams memory _claim, uint256 _localTotalShares, uint256 _localTotalPrincipal, string calldata _name ) internal returns (uint256) { _depositTokenIds.increment(); CreateClaimLocals memory locals = CreateClaimLocals({ newShares: _computeShares( _amount, _localTotalShares, _localTotalPrincipal ), claimerId: _claim.beneficiary, tokenId: _depositTokenIds.current() }); // Checks if the user is not already in debt if ( _computeShares( _applyLossTolerance(claimer[locals.claimerId].totalPrincipal), _localTotalShares, _localTotalPrincipal ) > claimer[locals.claimerId].totalShares ) revert VaultCannotDepositWhenClaimerInDebt(); claimer[locals.claimerId].totalShares += locals.newShares; claimer[locals.claimerId].totalPrincipal += _amount; totalShares += locals.newShares; totalPrincipal += _amount; deposits[locals.tokenId] = Deposit( _amount, msg.sender, locals.claimerId, _lockedUntil ); emit DepositMinted( locals.tokenId, _depositGroupId, _amount, locals.newShares, msg.sender, _claim.beneficiary, locals.claimerId, _lockedUntil, _claim.data, _name ); return locals.tokenId; } /** * Reduces the principal and shares of the claimer. * If there were any yield to be claimed, the claimer will also keep shares to withdraw later on. * * @notice This function doesn't transfer any funds, it only updates the state. * * @notice Only the owner of the deposit may call this function. * * @param _tokenId The deposit ID to withdraw from. * @param _totalShares The total shares to consider for the withdraw. * @param _totalUnderlyingMinusSponsored The total underlying to consider for the withdraw. * @param _to Where the funds will be sent * @param _force If the withdraw should still withdraw if there are not enough funds in the vault. * * @return the amount to withdraw. */ function _withdrawSingle( uint256 _tokenId, uint256 _totalShares, uint256 _totalUnderlyingMinusSponsored, address _to, bool _force, uint256 _amount ) internal returns (uint256) { if (deposits[_tokenId].owner != msg.sender) revert VaultNotOwnerOfDeposit(); // memoizing saves warm sloads Deposit memory _deposit = deposits[_tokenId]; Claimer memory _claim = claimer[_deposit.claimerId]; if (_deposit.lockedUntil > block.timestamp) revert VaultDepositLocked(); if (_deposit.claimerId == address(0)) revert VaultNotDeposit(); if (_deposit.amount < _amount) revert VaultCannotWithdrawMoreThanAvailable(); // Amount of shares the _amount is worth uint256 amountShares = _computeShares( _amount, _totalShares, _totalUnderlyingMinusSponsored ); // Amount of shares the _amount is worth taking in the claimer's // totalShares and totalPrincipal uint256 claimerShares = (_amount * _claim.totalShares) / _claim.totalPrincipal; if (!_force && amountShares > claimerShares) revert VaultMustUseForceWithdrawToAcceptLosses(); uint256 sharesToBurn = amountShares; if (_force && amountShares > claimerShares) sharesToBurn = claimerShares; claimer[_deposit.claimerId].totalShares -= sharesToBurn; claimer[_deposit.claimerId].totalPrincipal -= _amount; totalShares -= sharesToBurn; totalPrincipal -= _amount; bool isFull = _deposit.amount == _amount; if (isFull) { delete deposits[_tokenId]; } else { deposits[_tokenId].amount -= _amount; } uint256 amount = _computeAmount( sharesToBurn, _totalShares, _totalUnderlyingMinusSponsored ); emit DepositWithdrawn(_tokenId, sharesToBurn, amount, _to, isFull); return amount; } function _transferAndCheckInputToken( address _from, address _token, uint256 _amount ) internal { uint256 balanceBefore = IERC20(_token).balanceOf(address(this)); IERC20(_token).safeTransferFrom(_from, address(this), _amount); uint256 balanceAfter = IERC20(_token).balanceOf(address(this)); if (balanceAfter != balanceBefore + _amount) revert VaultAmountDoesNotMatchParams(); } function _blockTimestamp() internal view returns (uint64) { return uint64(block.timestamp); } /** * Computes amount of shares that will be received for a given deposit amount * * @param _amount Amount of deposit to consider. * @param _totalShares Amount of existing shares to consider. * @param _totalUnderlyingMinusSponsored Amount of existing underlying to consider. * @return Amount of shares the deposit will receive. */ function _computeShares( uint256 _amount, uint256 _totalShares, uint256 _totalUnderlyingMinusSponsored ) internal pure returns (uint256) { if (_amount == 0) return 0; if (_totalShares == 0) return _amount * SHARES_MULTIPLIER; if (_totalUnderlyingMinusSponsored == 0) revert VaultCannotComputeSharesWithoutPrincipal(); return (_amount * _totalShares) / _totalUnderlyingMinusSponsored; } /** * Computes the amount of underlying from a given number of shares * * @param _shares Number of shares. * @param _totalShares Amount of existing shares to consider. * @param _totalUnderlyingMinusSponsored Amounf of existing underlying to consider. * @return Amount that corresponds to the number of shares. */ function _computeAmount( uint256 _shares, uint256 _totalShares, uint256 _totalUnderlyingMinusSponsored ) internal pure returns (uint256) { if ( _shares == 0 || _totalShares == 0 || _totalUnderlyingMinusSponsored == 0 ) { return 0; } return ((_totalUnderlyingMinusSponsored * _shares) / _totalShares); } /** * Applies a loss tolerance to the given @param _amount. * * This function is used to prevent the vault from entering loss mode when funds are lost due to fees in the strategy. * For instance, the fees taken by Anchor. * * @param _amount Amount to apply the fees to. * * @return Amount with the fees applied. */ function _applyLossTolerance(uint256 _amount) internal view returns (uint256) { return _amount - _amount.pctOf(lossTolerancePct); } function sharesOf(address claimerId) external view returns (uint256) { return claimer[claimerId].totalShares; } function principalOf(address claimerId) external view returns (uint256) { return claimer[claimerId].totalPrincipal; } function pause() external onlyAdmin { _pause(); } function unpause() external onlyAdmin { _unpause(); } function exitPause() external onlyRole(DEFAULT_ADMIN_ROLE) { _exitPause(); } function exitUnpause() external onlyRole(DEFAULT_ADMIN_ROLE) { _exitUnpause(); } }
// 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 v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.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)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @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. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @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 revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { require(!paused(), "Pausable: paused"); } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { require(paused(), "Pausable: not paused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; interface IVault { // // Structs // struct ClaimParams { uint16 pct; address beneficiary; bytes data; } struct DepositParams { address inputToken; uint64 lockDuration; uint256 amount; ClaimParams[] claims; string name; uint256 slippage; } struct Deposit { /// amount of the deposit uint256 amount; /// wallet of the owner address owner; /// wallet of the claimer address claimerId; /// when can the deposit be withdrawn uint256 lockedUntil; } struct Claimer { uint256 totalPrincipal; uint256 totalShares; } // // Events // event DepositMinted( uint256 indexed id, uint256 groupId, uint256 amount, uint256 shares, address indexed depositor, address indexed claimer, address claimerId, uint64 lockedUntil, bytes data, string name ); event DepositWithdrawn( uint256 indexed id, uint256 shares, uint256 amount, address indexed to, bool burned ); event Invested(uint256 amount); event Disinvested(uint256 amount); event YieldClaimed( address claimerId, address indexed to, uint256 amount, uint256 burnedShares, uint256 perfFee, uint256 totalUnderlying, uint256 totalShares ); event FeeWithdrawn(uint256 amount); // // Public API // /** * Update the invested amount; */ function updateInvested() external; /** * Calculate maximum investable amount and already invested amount * * @return maxInvestableAmount maximum investable amount * @return alreadyInvested already invested amount */ function investState() external view returns (uint256 maxInvestableAmount, uint256 alreadyInvested); /** * Percentage of the total underlying to invest in the strategy */ function investPct() external view returns (uint16); /** * Underlying ERC20 token accepted by the vault */ function underlying() external view returns (IERC20Metadata); /** * Minimum lock period for each deposit */ function minLockPeriod() external view returns (uint64); /** * Total amount of underlying currently controlled by the * vault and the its strategy. */ function totalUnderlying() external view returns (uint256); /** * Total amount of shares */ function totalShares() external view returns (uint256); /** * Computes the amount of yield available for an an address. * * @param _to address to consider. * * @return claimable yield for @param _to, share of generated yield by @param _to, * and performance fee from generated yield */ function yieldFor(address _to) external view returns ( uint256, uint256, uint256 ); /** * Accumulate performance fee and transfers rest yield generated for the caller to * * @param _to Address that will receive the yield. */ function claimYield(address _to) external; /** * Creates a new deposit using the specified group id * * @param _groupId The group id for the new deposit * @param _params Deposit params */ function depositForGroupId(uint256 _groupId, DepositParams calldata _params) external returns (uint256[] memory); /** * Creates a new deposit * * @param _params Deposit params */ function deposit(DepositParams calldata _params) external returns (uint256[] memory); /** * Withdraws the principal from the deposits with the ids provided in @param _ids and sends it to @param _to. * * It fails if the vault is underperforming and there are not enough funds * to withdraw the expected amount. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. */ function withdraw(address _to, uint256[] calldata _ids) external; /** * Withdraws the principal from the deposits with the ids provided in @param _ids and sends it to @param _to. * * When the vault is underperforming it withdraws the funds with a loss. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. */ function forceWithdraw(address _to, uint256[] calldata _ids) external; /** * Withdraws any pending performance fee amount back to the treasury */ function withdrawPerformanceFee() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; interface IVaultSponsoring { // // Events // /// Emitted when a new sponsor deposit is created event Sponsored( uint256 indexed id, uint256 amount, address indexed depositor, uint256 lockedUntil ); /// Emitted when an existing sponsor withdraws event Unsponsored( uint256 indexed id, uint256 amount, address indexed to, bool burned ); /** * Total amount currently sponsored */ function totalSponsored() external view returns (uint256); /** * Creates a sponsored deposit with the amount provided in @param _amount. * Sponsored amounts will be invested like deposits, but unlike deposits * there are no claimers and the yield generated is donated to the vault. * The amount is locked until the timestamp specified in @param _lockedUntil. * * @param _inputToken The input token to deposit. * @param _amount Amount to sponsor. * @param _lockedUntil When the sponsor can unsponsor the amount. */ function sponsor( address _inputToken, uint256 _amount, uint256 _lockedUntil, uint256 _slippage ) external; /** * Withdraws the sponsored amount for the deposits with the ids provided * in @param _ids and sends it to @param _to. * * It fails if the vault is underperforming and there are not enough funds * to withdraw the sponsored amount. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. */ function unsponsor(address _to, uint256[] calldata _ids) external; /** * Withdraws the specified sponsored amounts @param _amounts for the deposits with the ids provided * in @param _ids and sends it to @param _to. * * @notice fails if there are not enough funds to withdraw the specified amounts. * * @param _to Address that will receive the funds. * @param _ids Array with the ids of the deposits. * @param _amounts Array with the amounts to withdraw. */ function partialUnsponsor( address _to, uint256[] calldata _ids, uint256[] calldata _amounts ) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; interface IVaultSettings { // // Events // event InvestPctUpdated(uint256 percentage); event TreasuryUpdated(address indexed treasury); event PerfFeePctUpdated(uint16 pct); event StrategyUpdated(address indexed strategy); event LossTolerancePctUpdated(uint16 pct); /** * Update invest percentage * * Emits {InvestPercentageUpdated} event * * @param _investPct the new invest percentage */ function setInvestPct(uint16 _investPct) external; /** * Changes the treasury used by the vault. * * @param _treasury the new strategy's address. */ function setTreasury(address _treasury) external; /** * Changes the performance fee used by the vault. * * @param _perfFeePct the new performance fee. */ function setPerfFeePct(uint16 _perfFeePct) external; /** * Changes the strategy used by the vault. * * @notice if there is invested funds in previous strategy, it is not allowed to set new strategy. * @param _strategy the new strategy's address. */ function setStrategy(address _strategy) external; /** * Changes the estimated investment fee used by the strategy. * * @param _pct the new investment fee estimated percentage. */ function setLossTolerancePct(uint16 _pct) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ICurve} from "../interfaces/curve/ICurve.sol"; /// Helper abstract contract to manage curve swaps abstract contract CurveSwapper { using SafeERC20 for IERC20; // // Structs // struct Swapper { /// Curve pool instance ICurve pool; /// decimals in token uint8 tokenDecimals; /// decimals in underlying uint8 underlyingDecimals; /// index of the deposit token we want to exchange to/from underlying int128 tokenI; /// index of underlying used by the vault (presumably always UST) int128 underlyingI; } struct SwapPoolParam { address token; address pool; int128 tokenI; int128 underlyingI; } // // Events // /// Emitted when a new swap pool is added event CurveSwapPoolAdded( address indexed token, address indexed pool, int128 tokenI, int128 underlyingI ); /// Emitted when a swap pool is removed event CurveSwapPoolRemoved(address indexed token); /// Emitted after every swap event Swap( address indexed fromToken, address indexed toToken, uint256 fromAmount, uint256 toAmount ); // // State // /// token => curve pool (for trading token/underlying) mapping(address => Swapper) public swappers; /// @return The address of the vault's main underlying token function getUnderlying() public view virtual returns (address); /// Swaps a given amount of /// Only works if the pool has previously been inserted into the contract /// /// @param _token The token we want to swap into /// @param _amount The amount of underlying we want to swap function _swapIntoUnderlying( address _token, uint256 _amount, uint256 _slippage ) internal returns (uint256 amount) { address underlyingToken = getUnderlying(); if (_token == underlyingToken) { // same token, nothing to do return _amount; } Swapper storage swapper = swappers[_token]; require( address(swapper.pool) != address(0x0), "non-existing swap pool" ); uint256 minAmount = _calcMinDy( _amount, swapper.tokenDecimals, swapper.underlyingDecimals, _slippage ); amount = swapper.pool.exchange_underlying( swapper.tokenI, swapper.underlyingI, _amount, minAmount ); emit Swap(_token, underlyingToken, _amount, amount); } /// Swaps a given amount of Underlying into a given token /// Only works if the pool has previously been inserted into the contract /// /// @param _token The token we want to swap into /// @param _amount The amount of underlying we want to swap function _swapFromUnderlying( address _token, uint256 _amount, uint256 _slippage ) internal returns (uint256 amount) { if (_token == getUnderlying()) { // same token, nothing to do return _amount; } Swapper storage swapper = swappers[_token]; uint256 minAmount = _calcMinDy( _amount, swapper.underlyingDecimals, swapper.tokenDecimals, _slippage ); amount = swapper.pool.exchange_underlying( swapper.underlyingI, swapper.tokenI, _amount, minAmount ); emit Swap(getUnderlying(), _token, _amount, amount); } function _calcMinDy( uint256 _amount, uint8 _fromDecimals, uint8 _toDecimals, uint256 _slippage ) internal pure returns (uint256) { return (_amount * _slippage * 10**_toDecimals) / (10**_fromDecimals * 10000); } /// This is necessary because some tokens (USDT) force you to approve(0) /// before approving a new amount meaning if we always approved blindly, /// then we could get random failures on the second attempt function _approveIfNecessary(address _token, address _pool) internal { uint256 allowance = IERC20(_token).allowance(address(this), _pool); if (allowance == 0) { IERC20(_token).safeApprove(_pool, type(uint256).max); } } /// @param _swapPools configs for each swap pool function _addPools(SwapPoolParam[] memory _swapPools) internal { uint256 length = _swapPools.length; for (uint256 i = 0; i < length; ++i) { _addPool(_swapPools[i]); } } function _addPool(SwapPoolParam memory _param) internal { require( address(swappers[_param.token].pool) == address(0), "token already has a swap pool" ); require( ICurve(_param.pool).coins(uint256(uint128(_param.underlyingI))) == getUnderlying(), "_underlyingI does not match underlying token" ); uint256 tokenDecimals = IERC20Metadata(_param.token).decimals(); uint256 underlyingDecimals = IERC20Metadata(getUnderlying()).decimals(); // TODO check if _token and _underlyingIndex match the pool settings swappers[_param.token] = Swapper( ICurve(_param.pool), uint8(tokenDecimals), uint8(underlyingDecimals), _param.tokenI, _param.underlyingI ); _approveIfNecessary(getUnderlying(), address(_param.pool)); _approveIfNecessary(_param.token, address(_param.pool)); emit CurveSwapPoolAdded( _param.token, _param.pool, _param.tokenI, _param.underlyingI ); } function _removePool(address _inputToken) internal { require( address(swappers[_inputToken].pool) != address(0), "pool does not exist" ); delete swappers[_inputToken]; emit CurveSwapPoolRemoved(_inputToken); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; library PercentMath { // Divisor used for representing percentages uint256 public constant PCT_DIVISOR = 10000; /** * @dev Returns whether an amount is a valid percentage out of PCT_DIVISOR * @param _amount Amount that is supposed to be a percentage */ function validPct(uint256 _amount) internal pure returns (bool) { return _amount <= PCT_DIVISOR; } /** * @dev Compute percentage of a value with the percentage represented by a fraction over PERC_DIVISOR * @param _amount Amount to take the percentage of * @param _fracNum Numerator of fraction representing the percentage with PCT_DIVISOR as the denominator */ function pctOf(uint256 _amount, uint16 _fracNum) internal pure returns (uint256) { return (_amount * _fracNum) / PCT_DIVISOR; } /** * @dev Checks if a given number corresponds to 100% * @param _perc Percentage value to check, with PCT_DIVISOR */ function is100Pct(uint256 _perc) internal pure returns (bool) { return _perc == PCT_DIVISOR; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/utils/Context.sol"; /** * @dev Contract module which allows children to implement an exit stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotExitPaused` and `whenExitPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract ExitPausable is Context { /** * @dev Emitted when the exitPause is triggered by `account`. */ event ExitPaused(address account); /** * @dev Emitted when the exitPause is lifted by `account`. */ event ExitUnpaused(address account); bool private _exitPaused; /** * @dev Initializes the contract in exitUnpaused state. */ constructor() { _exitPaused = false; } /** * @dev Modifier to make a function callable only when the contract is not exitPaused. * * Requirements: * * - The contract must not be exitPaused. */ modifier whenNotExitPaused() { _requireNotExitPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is exitPaused. * * Requirements: * * - The contract must be exitPaused. */ modifier whenExitPaused() { _requireExitPaused(); _; } /** * @dev Returns true if the contract is exitPaused, and false otherwise. */ function exitPaused() public view virtual returns (bool) { return _exitPaused; } /** * @dev Throws if the contract is exitPaused. */ function _requireNotExitPaused() internal view virtual { require(!exitPaused(), "Pausable: ExitPaused"); } /** * @dev Throws if the contract is not exitPaused. */ function _requireExitPaused() internal view virtual { require(exitPaused(), "Pausable: not ExitPaused"); } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be exitPaused. */ function _exitPause() internal virtual whenNotExitPaused { _exitPaused = true; emit ExitPaused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be exitPaused. */ function _exitUnpause() internal virtual whenExitPaused { _exitPaused = false; emit ExitUnpaused(_msgSender()); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * IStrategy defines the interface for pluggable contracts used by vaults to invest funds and generate yield. * * @notice It's up to the strategy to decide what do to with investable assets provided by a vault. * * @notice It's up to the vault to decide how much to invest/disinvest from the total pool. */ interface IStrategy { /** * Emmited when funds are invested by the strategy. * *@param amount amount invested */ event StrategyInvested(uint256 amount); /** * Emmited when funds are withdrawn (disinvested) by the strategy. * *@param amount amount withdrawn */ event StrategyWithdrawn(uint256 amount); /** * Provides information about wether the strategy is synchronous or asynchronous. * * @notice Synchronous strategies support instant withdrawals, * while asynchronous strategies impose a delay before withdrawals can be made. * * @return true if the strategy is synchronous, false otherwise */ function isSync() external view returns (bool); /** * The vault linked to this strategy. * * @return The vault's address */ function vault() external view returns (address); /** * Withdraws the specified amount back to the vault (disinvests) * * @param amount Amount to withdraw */ function withdrawToVault(uint256 amount) external; /** * Amount of the underlying currency currently invested by the strategy. * * @notice both held and invested amounts are included here, using the * latest known exchange rates to the underlying currency * * @return The total amount of underlying */ function investedAssets() external view returns (uint256); /** * Indicates if assets are invested into strategy or not. * * @notice this will be used when removing the strategy from the vault * @return true if assets invested, false if nothing invested. */ function hasAssets() external view returns (bool); /** * Deposits of all the available underlying into the yield generating protocol. */ function invest() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; interface CustomErrors { // // Vault Errors // // Vault: sender is not the owner of the group id error VaultSenderNotOwnerOfGroupId(); // Vault: invalid investPct error VaultInvalidInvestpct(); // Vault: invalid performance fee error VaultInvalidPerformanceFee(); // Vault: no performance fee error VaultNoPerformanceFee(); // Vault: invalid lossTolerance error VaultInvalidLossTolerance(); // Vault: underlying cannot be 0x0 error VaultUnderlyingCannotBe0Address(); // Vault: treasury cannot be 0x0 error VaultTreasuryCannotBe0Address(); // Vault: admin cannot be 0x0 error VaultAdminCannotBe0Address(); // Vault: cannot transfer admin rights to self error VaultCannotTransferAdminRightsToSelf(); // Vault: caller is not admin error VaultCallerNotAdmin(); // Vault: caller is not settings error VaultCallerNotSettings(); // Vault: caller is not keeper error VaultCallerNotKeeper(); // Vault: caller is not sponsor error VaultCallerNotSponsor(); // Vault: destination address is 0x error VaultDestinationCannotBe0Address(); // Vault: strategy is not set error VaultStrategyNotSet(); // Vault: invalid minLockPeriod error VaultInvalidMinLockPeriod(); // Vault: invalid lock period error VaultInvalidLockPeriod(); // Vault: cannot deposit 0 error VaultCannotDeposit0(); // Vault: cannot sponsor 0 error VaultCannotSponsor0(); // Vault: cannot deposit when yield is negative error VaultCannotDepositWhenYieldNegative(); // Vault: cannot deposit when the claimer is in debt error VaultCannotDepositWhenClaimerInDebt(); // Vault: cannot withdraw when yield is negative error VaultCannotWithdrawWhenYieldNegative(); // Vault: nothing to do error VaultNothingToDo(); // Vault: not enough to rebalance error VaultNotEnoughToRebalance(); // Vault: invalid vault error VaultInvalidVault(); // Vault: strategy has invested funds error VaultStrategyHasInvestedFunds(); // Vault: not enough funds error VaultNotEnoughFunds(); // Vault: you are not allowed error VaultNotAllowed(); // Vault: amount is locked error VaultAmountLocked(); // Vault: deposit is locked error VaultDepositLocked(); // Vault: token id is not a sponsor error VaultNotSponsor(); // Vault: token id is not a deposit error VaultNotDeposit(); // Vault: claim percentage cannot be 0 error VaultClaimPercentageCannotBe0(); // Vault: claimer cannot be address 0 error VaultClaimerCannotBe0(); // Vault: claims don't add up to 100% error VaultClaimsDontAddUp(); // Vault: you are not the owner of a deposit error VaultNotOwnerOfDeposit(); // Vault: cannot withdraw more than the available amount error VaultCannotWithdrawMoreThanAvailable(); // Vault: must force withdraw to withdraw with a loss error VaultMustUseForceWithdrawToAcceptLosses(); // Vault: amount received does not match params error VaultAmountDoesNotMatchParams(); // Vault: cannot compute shares when there's no principal error VaultCannotComputeSharesWithoutPrincipal(); // Vault: deposit name for MetaVault too short error VaultDepositNameTooShort(); // Vault: no yield to claim error VaultNoYieldToClaim(); // // Strategy Errors // // Strategy: admin is 0x error StrategyAdminCannotBe0Address(); // Strategy: cannot transfer admin rights to self error StrategyCannotTransferAdminRightsToSelf(); // Strategy: underlying is 0x error StrategyUnderlyingCannotBe0Address(); // Strategy: not an IVault error StrategyNotIVault(); // Strategy: caller is not manager error StrategyCallerNotManager(); // Strategy: caller has no settings role error StrategyCallerNotSettings(); // Strategy: caller is not admin error StrategyCallerNotAdmin(); // Strategy: amount is 0 error StrategyAmountZero(); // Strategy: not running error StrategyNotRunning(); // Not Enough Underlying Balance in Strategy contract error StrategyNoUnderlying(); // Not Enough Shares in Strategy Contract error StrategyNotEnoughShares(); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.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 /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// 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: 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 (last updated v4.7.0) (utils/Strings.sol) pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.10; interface ICurve { function exchange_underlying( int128 i, int128 j, uint256 dx, uint256 min_dy ) external returns (uint256); function coins(uint256 i) external view returns (address); }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC20Metadata","name":"_underlying","type":"address"},{"internalType":"uint64","name":"_minLockPeriod","type":"uint64"},{"internalType":"uint16","name":"_investPct","type":"uint16"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"uint16","name":"_perfFeePct","type":"uint16"},{"internalType":"uint16","name":"_lossTolerancePct","type":"uint16"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"int128","name":"tokenI","type":"int128"},{"internalType":"int128","name":"underlyingI","type":"int128"}],"internalType":"struct CurveSwapper.SwapPoolParam[]","name":"_swapPools","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"StrategyAdminCannotBe0Address","type":"error"},{"inputs":[],"name":"StrategyAmountZero","type":"error"},{"inputs":[],"name":"StrategyCallerNotAdmin","type":"error"},{"inputs":[],"name":"StrategyCallerNotManager","type":"error"},{"inputs":[],"name":"StrategyCallerNotSettings","type":"error"},{"inputs":[],"name":"StrategyCannotTransferAdminRightsToSelf","type":"error"},{"inputs":[],"name":"StrategyNoUnderlying","type":"error"},{"inputs":[],"name":"StrategyNotEnoughShares","type":"error"},{"inputs":[],"name":"StrategyNotIVault","type":"error"},{"inputs":[],"name":"StrategyNotRunning","type":"error"},{"inputs":[],"name":"StrategyUnderlyingCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultAdminCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultAmountDoesNotMatchParams","type":"error"},{"inputs":[],"name":"VaultAmountLocked","type":"error"},{"inputs":[],"name":"VaultCallerNotAdmin","type":"error"},{"inputs":[],"name":"VaultCallerNotKeeper","type":"error"},{"inputs":[],"name":"VaultCallerNotSettings","type":"error"},{"inputs":[],"name":"VaultCallerNotSponsor","type":"error"},{"inputs":[],"name":"VaultCannotComputeSharesWithoutPrincipal","type":"error"},{"inputs":[],"name":"VaultCannotDeposit0","type":"error"},{"inputs":[],"name":"VaultCannotDepositWhenClaimerInDebt","type":"error"},{"inputs":[],"name":"VaultCannotDepositWhenYieldNegative","type":"error"},{"inputs":[],"name":"VaultCannotSponsor0","type":"error"},{"inputs":[],"name":"VaultCannotTransferAdminRightsToSelf","type":"error"},{"inputs":[],"name":"VaultCannotWithdrawMoreThanAvailable","type":"error"},{"inputs":[],"name":"VaultCannotWithdrawWhenYieldNegative","type":"error"},{"inputs":[],"name":"VaultClaimPercentageCannotBe0","type":"error"},{"inputs":[],"name":"VaultClaimerCannotBe0","type":"error"},{"inputs":[],"name":"VaultClaimsDontAddUp","type":"error"},{"inputs":[],"name":"VaultDepositLocked","type":"error"},{"inputs":[],"name":"VaultDepositNameTooShort","type":"error"},{"inputs":[],"name":"VaultDestinationCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultInvalidInvestpct","type":"error"},{"inputs":[],"name":"VaultInvalidLockPeriod","type":"error"},{"inputs":[],"name":"VaultInvalidLossTolerance","type":"error"},{"inputs":[],"name":"VaultInvalidMinLockPeriod","type":"error"},{"inputs":[],"name":"VaultInvalidPerformanceFee","type":"error"},{"inputs":[],"name":"VaultInvalidVault","type":"error"},{"inputs":[],"name":"VaultMustUseForceWithdrawToAcceptLosses","type":"error"},{"inputs":[],"name":"VaultNoPerformanceFee","type":"error"},{"inputs":[],"name":"VaultNoYieldToClaim","type":"error"},{"inputs":[],"name":"VaultNotAllowed","type":"error"},{"inputs":[],"name":"VaultNotDeposit","type":"error"},{"inputs":[],"name":"VaultNotEnoughFunds","type":"error"},{"inputs":[],"name":"VaultNotEnoughToRebalance","type":"error"},{"inputs":[],"name":"VaultNotOwnerOfDeposit","type":"error"},{"inputs":[],"name":"VaultNotSponsor","type":"error"},{"inputs":[],"name":"VaultNothingToDo","type":"error"},{"inputs":[],"name":"VaultSenderNotOwnerOfGroupId","type":"error"},{"inputs":[],"name":"VaultStrategyHasInvestedFunds","type":"error"},{"inputs":[],"name":"VaultStrategyNotSet","type":"error"},{"inputs":[],"name":"VaultTreasuryCannotBe0Address","type":"error"},{"inputs":[],"name":"VaultUnderlyingCannotBe0Address","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"int128","name":"tokenI","type":"int128"},{"indexed":false,"internalType":"int128","name":"underlyingI","type":"int128"}],"name":"CurveSwapPoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"CurveSwapPoolRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"groupId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"address","name":"claimerId","type":"address"},{"indexed":false,"internalType":"uint64","name":"lockedUntil","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"DepositMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"burned","type":"bool"}],"name":"DepositWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Disinvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"ExitPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"ExitUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"InvestPctUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Invested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"pct","type":"uint16"}],"name":"LossTolerancePctUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"pct","type":"uint16"}],"name":"PerfFeePctUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"name":"Sponsored","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"StrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromToken","type":"address"},{"indexed":true,"internalType":"address","name":"toToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"fromAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toAmount","type":"uint256"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"bool","name":"burned","type":"bool"}],"name":"Unsponsored","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"claimerId","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burnedShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"perfFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"YieldClaimed","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KEEPER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DEPOSIT_LOCK_DURATION","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SPONSOR_LOCK_DURATION","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_SPONSOR_LOCK_DURATION","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SETTINGS_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHARES_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPONSOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulatedPerfFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"int128","name":"tokenI","type":"int128"},{"internalType":"int128","name":"underlyingI","type":"int128"}],"internalType":"struct CurveSwapper.SwapPoolParam","name":"_param","type":"tuple"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"claimYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"claimer","outputs":[{"internalType":"uint256","name":"totalPrincipal","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint64","name":"lockDuration","type":"uint64"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint16","name":"pct","type":"uint16"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IVault.ClaimParams[]","name":"claims","type":"tuple[]"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"internalType":"struct IVault.DepositParams","name":"_params","type":"tuple"}],"name":"deposit","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_groupId","type":"uint256"},{"components":[{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint64","name":"lockDuration","type":"uint64"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"internalType":"uint16","name":"pct","type":"uint16"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IVault.ClaimParams[]","name":"claims","type":"tuple[]"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"internalType":"struct IVault.DepositParams","name":"_params","type":"tuple"}],"name":"depositForGroupId","outputs":[{"internalType":"uint256[]","name":"depositIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"depositGroupIdOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"claimerId","type":"address"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exitPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitUnpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"forceWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"investPct","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"investState","outputs":[{"internalType":"uint256","name":"maxInvestableAmount","type":"uint256"},{"internalType":"uint256","name":"alreadyInvested","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossTolerancePct","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLockPeriod","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"partialUnsponsor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"partialWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"perfFeePct","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"claimerId","type":"address"}],"name":"principalOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_inputToken","type":"address"}],"name":"removePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_investPct","type":"uint16"}],"name":"setInvestPct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"pct","type":"uint16"}],"name":"setLossTolerancePct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_perfFeePct","type":"uint16"}],"name":"setPerfFeePct","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"setStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"claimerId","type":"address"}],"name":"sharesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_inputToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"uint256","name":"_slippage","type":"uint256"}],"name":"sponsor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"contract IStrategy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"swappers","outputs":[{"internalType":"contract ICurve","name":"pool","type":"address"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"internalType":"uint8","name":"underlyingDecimals","type":"uint8"},{"internalType":"int128","name":"tokenI","type":"int128"},{"internalType":"int128","name":"underlyingI","type":"int128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPrincipal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSponsored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlyingMinusSponsored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newAdmin","type":"address"}],"name":"transferAdminRights","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"unsponsor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateInvested","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"yieldFor","outputs":[{"internalType":"uint256","name":"claimableYield","type":"uint256"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"perfFee","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b50604051620065c3380380620065c3833981016040819052620000349162000d80565b60016002556003805461ffff191690556200005f61ffff871662000390602090811b6200241617901c565b6200007d5760405163870e44a360e01b815260040160405180910390fd5b620000978361ffff166200039060201b620024161760201c565b620000b55760405163d25b1e4b60e01b815260040160405180910390fd5b620000cf8261ffff166200039060201b620024161760201c565b620000ed57604051631d05623160e01b815260040160405180910390fd5b6001600160a01b0388166200011557604051631fc8ba7960e31b815260040160405180910390fd5b6001600160a01b0385166200013d576040516335af31e960e11b815260040160405180910390fd5b6001600160a01b03841662000165576040516330c9889360e01b815260040160405180910390fd5b6001600160401b038716158062000187575062dd7c006001600160401b038816115b15620001a657604051636df7cef760e11b815260040160405180910390fd5b620001b360008562000398565b620001df7ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab8562000398565b6200020b7ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf6030958562000398565b620002377f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a8562000398565b6003805462010000600160c01b031916600160b01b61ffff8981169190910262010000600160b01b03191691909117620100006001600160a01b038c811682029290921793849055600d80546001600160401b038d166080528a84166001600160b01b031990911617600160a01b89861602179055600f805461ffff1916938716939093179092556040805163313ce56760e01b8152905192909304169163313ce5679160048083019260209291908290030181865afa15801562000300573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000326919062000f38565b6200033390600a62001070565b6200034090600a62001081565b60a0526200034e8162000407565b6040516001600160a01b038616907f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d190600090a25050505050505050620011bb565b612710101590565b620003a482826200045a565b620004035760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45b5050565b805160005b818110156200045557620004428382815181106200042e576200042e620010a3565b60200260200101516200048760201b60201c565b6200044d81620010b9565b90506200040c565b505050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff165b92915050565b80516001600160a01b039081166000908152602081905260409020541615620004f75760405162461bcd60e51b815260206004820152601d60248201527f746f6b656e20616c7265616479206861732061207377617020706f6f6c00000060448201526064015b60405180910390fd5b620005106003546201000090046001600160a01b031690565b6001600160a01b031681602001516001600160a01b031663c661065783606001516001600160801b03166040518263ffffffff1660e01b81526004016200055991815260200190565b602060405180830381865afa15801562000577573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200059d9190620010d7565b6001600160a01b0316146200060a5760405162461bcd60e51b815260206004820152602c60248201527f5f756e6465726c79696e674920646f6573206e6f74206d6174636820756e646560448201526b39363cb4b733903a37b5b2b760a11b6064820152608401620004ee565b600081600001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200064f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000675919062000f38565b60ff1690506000620006956003546201000090046001600160a01b031690565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620006d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006f9919062000f38565b6040805160a0810182526020808701516001600160a01b03908116835260ff8781168385019081529581168486018181528a870151600f90810b60608089019182528d015190910b608088019081528c5186166000908152968790529790952095518654985191518416600160a81b0260ff60a81b1992909416600160a01b026001600160a81b031990991694169390931796909617919091161782555191516001600160801b03908116600160801b029216919091176001909101559050620007e0620007d56003546201000090046001600160a01b031690565b602085015162000865565b82516020840151620007f3919062000865565b82602001516001600160a01b031683600001516001600160a01b03167f1576b5fcfa863788d9ef6558cab7aa68d4b48c44eb7bacaf1a8ac6d6b9d26f948560400151866060015160405162000858929190600f92830b8152910b602082015260400190565b60405180910390a3505050565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa158015620008b6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008dc9190620010f7565b90508062000455576200045582600019856001600160a01b03166200090b60201b6200241e179092919060201c565b801580620009895750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801562000961573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620009879190620010f7565b155b620009fd5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401620004ee565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526200045591859162000a5516565b600062000ab1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662000b3360201b6200259b179092919060201c565b80519091501562000455578080602001905181019062000ad2919062001111565b620004555760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620004ee565b606062000b44848460008562000b4e565b90505b9392505050565b60608247101562000bb15760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620004ee565b6001600160a01b0385163b62000c0a5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620004ee565b600080866001600160a01b0316858760405162000c28919062001168565b60006040518083038185875af1925050503d806000811462000c67576040519150601f19603f3d011682016040523d82523d6000602084013e62000c6c565b606091505b50909250905062000c7f82828662000c8a565b979650505050505050565b6060831562000c9b57508162000b47565b82511562000cac5782518084602001fd5b8160405162461bcd60e51b8152600401620004ee919062001186565b6001600160a01b038116811462000cde57600080fd5b50565b805161ffff8116811462000cf457600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171562000d345762000d3462000cf9565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000d655762000d6562000cf9565b604052919050565b8051600f81900b811462000cf457600080fd5b600080600080600080600080610100898b03121562000d9e57600080fd5b885162000dab8162000cc8565b60208a01519098506001600160401b03808216821462000dca57600080fd5b81985062000ddb60408c0162000ce1565b975060608b0151915062000def8262000cc8565b60808b015191965062000e028262000cc8565b81955062000e1360a08c0162000ce1565b945062000e2360c08c0162000ce1565b935060e08b015191508082111562000e3a57600080fd5b818b0191508b601f83011262000e4f57600080fd5b81518181111562000e645762000e6462000cf9565b62000e7560208260051b0162000d3a565b91508181835260208301925060208260071b85010191508d82111562000e9a57600080fd5b6020840193505b8184101562000f24576080848f03121562000ebb57600080fd5b62000ec562000d0f565b845162000ed28162000cc8565b8152602085015162000ee48162000cc8565b602082015262000ef76040860162000d6d565b604082015262000f0a6060860162000d6d565b606082015283526080939093019260209092019162000ea1565b809450505050509295985092959890939650565b60006020828403121562000f4b57600080fd5b815160ff8116811462000b4757600080fd5b634e487b7160e01b600052601160045260246000fd5b600181815b8085111562000fb457816000190482111562000f985762000f9862000f5d565b8085161562000fa657918102915b93841c939080029062000f78565b509250929050565b60008262000fcd5750600162000481565b8162000fdc5750600062000481565b816001811462000ff55760028114620010005762001020565b600191505062000481565b60ff84111562001014576200101462000f5d565b50506001821b62000481565b5060208310610133831016604e8410600b841016171562001045575081810a62000481565b62001051838362000f73565b806000190482111562001068576200106862000f5d565b029392505050565b600062000b4760ff84168362000fbc565b60008160001904831182151516156200109e576200109e62000f5d565b500290565b634e487b7160e01b600052603260045260246000fd5b6000600019821415620010d057620010d062000f5d565b5060010190565b600060208284031215620010ea57600080fd5b815162000b478162000cc8565b6000602082840312156200110a57600080fd5b5051919050565b6000602082840312156200112457600080fd5b8151801515811462000b4757600080fd5b60005b838110156200115257818101518382015260200162001138565b8381111562001162576000848401525b50505050565b600082516200117c81846020870162001135565b9190910192915050565b6020815260008251806020840152620011a781604085016020870162001135565b601f01601f19169190910160400192915050565b60805160a0516153d4620011ef600039600081816110d401526111bf0152600081816105dd01526131e701526153d46000f3fe608060405234801561001057600080fd5b50600436106103af5760003560e01c80638456cb59116101f4578063c0ddb6921161011a578063df6f9ba7116100ad578063f5eb42dc1161007c578063f5eb42dc14610951578063f62898871461097d578063f78797c0146109a4578063fd6e9217146109cd57600080fd5b8063df6f9ba71461090f578063e4020fdf14610922578063eb0ebfbc14610935578063f0f442601461093e57600080fd5b8063cd0d9ba8116100e9578063cd0d9ba8146108c1578063cda2695a146108d4578063d547741f146108e7578063d9db2b77146108fa57600080fd5b8063c0ddb69214610877578063c2d794441461087f578063c70920bc146108a6578063cd00dd41146108ae57600080fd5b8063a217fddf11610192578063b5106add11610161578063b5106add14610816578063b59a40cb14610829578063bba97d3314610849578063bd2e3ecd1461061857600080fd5b8063a217fddf14610779578063a8c62e7614610781578063abaa9d7014610794578063b02c43d0146107a457600080fd5b80639816f473116101ce5780639816f47314610732578063999927df14610749578063a164c25d1461075c578063a1ac20eb1461076657600080fd5b80638456cb591461065b5780638cad7fbe1461066357806391d14854146106f957600080fd5b80634e813ac4116102d957806361e20a1c1161027757806376490b561161024657806376490b56146106185780637e2cba6f146106225780637e4b8da0146106355780638293744b1461064857600080fd5b806361e20a1c146105755780636e7007e61461059e5780636f307dc3146105bf57806373ae54b5146105d857600080fd5b80635c975abb116102b35780635c975abb1461052f5780635cb0d4061461053a5780635e8486551461054257806361d027b31461054a57600080fd5b80634e813ac41461050c5780634fc78d6814610514578063563233f61461051c57600080fd5b8063364bc15a116103515780633ba52fc6116103205780633ba52fc6146104e05780633f383236146104e85780633f4ba83a146104fb5780634b1533b21461050357600080fd5b8063364bc15a1461048a57806336568abe146104b15780633a98ef39146104c45780633b7d0946146104cd57600080fd5b806319d3ee3d1161038d57806319d3ee3d14610435578063248a9ca31461043e5780632f2ff15d1461046257806333a100ca1461047757600080fd5b806301ffc9a7146103b45780631325d5f1146103dc57806313f6686d146103f9575b600080fd5b6103c76103c23660046149a8565b6109e2565b60405190151581526020015b60405180910390f35b6103eb670de0b6b3a764000081565b6040519081526020016103d3565b6104206104073660046149e7565b600b602052600090815260409020805460019091015482565b604080519283526020830191909152016103d3565b6103eb600e5481565b6103eb61044c366004614a04565b6000908152600160208190526040909120015490565b610475610470366004614a1d565b610a5a565b005b6104756104853660046149e7565b610a85565b6103eb7ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab81565b6104756104bf366004614a1d565b610cb4565b6103eb60055481565b6104756104db3660046149e7565b610d45565b610475610da0565b6104756104f6366004614ad4565b610e8d565b610475610ee5565b6103eb600c5481565b610420610f3e565b610475610ffb565b61047561052a366004614b67565b6112ba565b60035460ff166103c7565b6104756113ba565b6104756113cd565b600d5461055d906001600160a01b031681565b6040516001600160a01b0390911681526020016103d3565b6103eb6105833660046149e7565b6001600160a01b03166000908152600b602052604090205490565b600f546105ac9061ffff1681565b60405161ffff90911681526020016103d3565b60035461055d906201000090046001600160a01b031681565b6105ff7f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff90911681526020016103d3565b6105ff62dd7c0081565b610475610630366004614b67565b6113e0565b610475610643366004614bce565b6114b3565b610475610656366004614c51565b611551565b610475611630565b6106ba6106713660046149e7565b600060208190529081526040902080546001909101546001600160a01b0382169160ff600160a01b8204811692600160a81b9092041690600f81810b91600160801b9004900b85565b604080516001600160a01b03909616865260ff94851660208701529390921692840192909252600f91820b6060840152900b608082015260a0016103d3565b6103c7610707366004614a1d565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6003546201000090046001600160a01b031661055d565b6104756107573660046149e7565b611687565b6105ff6212750081565b610475610774366004614b67565b61185a565b6103eb600081565b60065461055d906001600160a01b031681565b600354610100900460ff166103c7565b6107e66107b2366004614a04565b600960205260009081526040902080546001820154600283015460039093015491926001600160a01b039182169291169084565b6040516103d394939291909384526001600160a01b03928316602085015291166040830152606082015260800190565b6104756108243660046149e7565b61195c565b61083c610837366004614cbe565b611b40565b6040516103d39190614cfb565b61085c6108573660046149e7565b611be5565b604080519384526020840192909252908201526060016103d3565b6103eb611ca4565b6103eb7f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a81565b6103eb611ce7565b6104756108bc366004614bce565b611e63565b61083c6108cf366004614d3f565b611ef5565b6104756108e2366004614d86565b611faf565b6104756108f5366004614a1d565b6121f5565b600d546105ac90600160a01b900461ffff1681565b61047561091d366004614c51565b61221b565b610475610930366004614c51565b6122ad565b6103eb60045481565b61047561094c3660046149e7565b61233d565b6103eb61095f3660046149e7565b6001600160a01b03166000908152600b602052604090206001015490565b6103eb7ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf60309581565b61055d6109b2366004614a04565b6008602052600090815260409020546001600160a01b031681565b6003546105ac90600160b01b900461ffff1681565b60006001600160e01b031982167f21d982ed000000000000000000000000000000000000000000000000000000001480610a4557506001600160e01b031982167f0fae047800000000000000000000000000000000000000000000000000000000145b80610a545750610a54826125b4565b92915050565b60008281526001602081905260409091200154610a768161261b565b610a808383612625565b505050565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff16610ad457604051631e15456f60e11b815260040160405180910390fd5b6001600160a01b038116610afb57604051634f08b3f360e11b815260040160405180910390fd5b306001600160a01b0316816001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b679190614dc1565b6001600160a01b031614610ba7576040517f0251bab500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546001600160a01b031615801590610c335750600660009054906101000a90046001600160a01b03166001600160a01b0316635be9b2d36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c339190614dde565b15610c6a576040517fd28a9fdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517f4da9c22c924692646a21cf1f423781ae3285198dc22e8a6912835d3272b90b3c90600090a250565b6001600160a01b0381163314610d375760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610d4182826126ac565b5050565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff16610d9457604051631bacfc6960e01b815260040160405180910390fd5b610d9d8161272f565b50565b3360009081527f10c15aae13326e9b33c92ffbb94efb7492c500f0cca324caca9bd1aca194ed18602052604090205460ff16610def57604051637660f80560e11b815260040160405180910390fd5b600e5480610e29576040517f0a33934000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600e55610e3781612803565b6040518181527fb7eeacba6b133788365610e83d3f130d07b6ef6e78877961f25b3f61fcba07529060200160405180910390a1600d54600354610d9d916001600160a01b03620100009092048216911683612a02565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff16610edc57604051631bacfc6960e01b815260040160405180910390fd5b610d9d81612a4b565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff16610f3457604051631bacfc6960e01b815260040160405180910390fd5b610f3c612e62565b565b60065460009081906001600160a01b0316610f5c5750600091829150565b600354610f7c90600160b01b900461ffff16610f76611ce7565b90612eb4565b9150600660009054906101000a90046001600160a01b03166001600160a01b0316634ad0b6846040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff59190614e00565b90509091565b3360009081527f10c15aae13326e9b33c92ffbb94efb7492c500f0cca324caca9bd1aca194ed18602052604090205460ff1661104a57604051637660f80560e11b815260040160405180910390fd5b6006546001600160a01b031661107357604051634f08b3f360e11b815260040160405180910390fd5b60008061107e610f3e565b91509150808214156110bc576040517ff096593000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818111156111af5760006110d08383614e2f565b90507f000000000000000000000000000000000000000000000000000000000000000081101561111357604051630e33bdb760e11b815260040160405180910390fd5b6006546040516319d1885d60e31b8152600481018390526001600160a01b039091169063ce8c42e890602401600060405180830381600087803b15801561115957600080fd5b505af115801561116d573d6000803e3d6000fd5b505050507ff7e72e2f53a982a67fc999c00edfd87a94bdf99e5031c74851276cfd65b0bd29816040516111a291815260200190565b60405180910390a1505050565b60006111bb8284614e2f565b90507f00000000000000000000000000000000000000000000000000000000000000008110156111fe57604051630e33bdb760e11b815260040160405180910390fd5b600654600354611221916001600160a01b03620100009092048216911683612a02565b600660009054906101000a90046001600160a01b03166001600160a01b031663e8b5e51f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561127157600080fd5b505af1158015611285573d6000803e3d6000fd5b505050507fac9f7997c30b6a3cc9c74953898b5de154359339c7ec0d6d70ceb98e55db1a4b816040516111a291815260200190565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff1661130957604051631e15456f60e11b815260040160405180910390fd5b61ffff81166127101015611349576040517fd25b1e4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff16600160a01b61ffff8416908102919091179091556040519081527f16de0efbdf16c568a60b65978ed774bba4e0c179de55ab8f639527e41fd0c861906020015b60405180910390a150565b60006113c58161261b565b610d9d612ed1565b60006113d88161261b565b610d9d612f10565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff1661142f57604051631e15456f60e11b815260040160405180910390fd5b61ffff8116612710101561146f576040517f1d05623100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f805461ffff191661ffff83169081179091556040519081527f5b9aa28fc994f782b33ebebd9947795b5bc59a54203466433eac5f8d9e819400906020016113af565b6002805414156115055760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611511612f4a565b6001600160a01b0385166115385760405163f95106ab60e01b815260040160405180910390fd5b6115458585858585612fa2565b50506001600255505050565b6002805414156115a35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b600280556115af612f4a565b6001600160a01b0383166115d65760405163f95106ab60e01b815260040160405180910390fd5b6115de611ca4565b600c541115611619576040517f0bdd660c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611626838383600061304b565b5050600160025550565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff1661167f57604051631bacfc6960e01b815260040160405180910390fd5b610f3c61310f565b6002805414156116d95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b600280556116e5612f4a565b6001600160a01b03811661170c5760405163f95106ab60e01b815260040160405180910390fd5b600080600061171a33611be5565b925092509250826000141561175b576040517f58367fe100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611765611ca4565b90506000600554905082600e60008282546117809190614e46565b9091555061178f905085612803565b6003546117ac906201000090046001600160a01b03168787612a02565b336000908152600b6020526040812060010180548692906117ce908490614e2f565b9250508190555083600560008282546117e79190614e2f565b90915550506040805133815260208101879052908101859052606081018490526080810183905260a081018290526001600160a01b038716907f4344accc2a634cf29195bba6fa3d939e3415ecd1ca5c57b322bcf81f920979c89060c00160405180910390a25050600160025550505050565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff166118a957604051631e15456f60e11b815260040160405180910390fd5b61ffff811661271010156118e9576040517f870e44a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405161ffff821681527f40775ca73a6e168d23747bc0200694cf7c99ad2db624d04c095cb59899011a569060200160405180910390a16003805461ffff909216600160b01b027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff166119ab57604051631bacfc6960e01b815260040160405180910390fd5b6001600160a01b0381166119eb576040517f30c9889300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116331415611a2e576040517f25499f7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a39600082612625565b611a637ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab82612625565b611a8d7ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf60309582612625565b611ab77f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a82612625565b611ac26000336126ac565b611aec7ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab336126ac565b611b167ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf603095336126ac565b610d9d7f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a336126ac565b6060600280541415611b945760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611ba061314c565b600754611bae816001614e46565b600755600081815260086020526040902080546001600160a01b03191633179055611bd9818461319f565b60016002559392505050565b6001600160a01b0381166000908152600b6020526040812080546001909101548291829182611c12611ca4565b90506000611c238360055484613392565b9050838111611c4057600080600096509650965050505050611c9d565b6000611c4c8583614e2f565b9050611c5b81600554856133ca565b96506000611c6c8860055486613392565b600d54909150611c88908290600160a01b900461ffff16612eb4565b9650611c948782614e2f565b98505050505050505b9193909250565b600080611caf611ce7565b90506000600e54600454611cc39190614e46565b905081811115611cd65760009250505090565b611ce08183614e2f565b9250505090565b6006546000906001600160a01b031615611df257600660009054906101000a90046001600160a01b03166001600160a01b0316634ad0b6846040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d729190614e00565b6003546040516370a0823160e01b8152306004820152620100009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de39190614e00565b611ded9190614e46565b905090565b6003546040516370a0823160e01b8152306004820152620100009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611e3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ded9190614e00565b600280541415611eb55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611ec1612f4a565b6001600160a01b038516611ee85760405163f95106ab60e01b815260040160405180910390fd5b6115458585858585613439565b6060600280541415611f495760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611f5561314c565b6000838152600860205260409020546001600160a01b03163314611fa5576040517f9049b68600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bd9838361319f565b6002805414156120015760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b600280553360009081527f27365024d84ecf053ef4d13025b66be161b03e90a7fc7ff54f74d5533a9f857e602052604090205460ff1661206d576040517f9aff7af000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61207561314c565b826120ac576040517ff712805800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b621275008210806120bf575062dd7c0082115b156120dd57604051636235acd960e01b815260040160405180910390fd5b60006120e94284614e46565b90506120f9600a80546001019055565b6000612104600a5490565b90506121113387876134c7565b600061211e8787866135ff565b604080516080810182528281523360208083019182526000838501818152606085018a815289835260099093529481209351845591516001840180546001600160a01b03199081166001600160a01b0393841617909155945160028501805490961691161790935591516003909101556004805492935083929091906121a5908490614e46565b90915550506040805182815260208101859052339184917f7ca3497675c6d3ec00b1edc13b8e0b06169ee96a663ab25a74af7da53378f09e910160405180910390a3505060016002555050505050565b600082815260016020819052604090912001546122118161261b565b610a8083836126ac565b60028054141561226d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055612279612f4a565b6001600160a01b0383166122a05760405163f95106ab60e01b815260040160405180910390fd5b611626838383600161304b565b6002805414156122ff5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b6002805561230b612f4a565b6001600160a01b0383166123325760405163f95106ab60e01b815260040160405180910390fd5b6116268383836137df565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff1661238c57604051631e15456f60e11b815260040160405180910390fd5b6001600160a01b0381166123cc576040517f6b5e63d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80546001600160a01b0319166001600160a01b0383169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d190600090a250565b612710101590565b8015806124985750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124969190614e00565b155b61250a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610d2e565b6040516001600160a01b038316602482015260448101829052610a809084907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915261385a565b60606125aa848460008561393f565b90505b9392505050565b60006001600160e01b031982167f7965db0b000000000000000000000000000000000000000000000000000000001480610a5457507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610a54565b610d9d8133613a7c565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16610d415760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff1615610d415760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b03818116600090815260208190526040902054166127965760405162461bcd60e51b815260206004820152601360248201527f706f6f6c20646f6573206e6f74206578697374000000000000000000000000006044820152606401610d2e565b6001600160a01b03811660008181526020819052604080822080547fffffffffffffffffffff00000000000000000000000000000000000000000000168155600101829055517f94be23730c4398d20227f4e457cf92307b13e5956f2a958e2e368ad44e2f826b9190a250565b6003546040516370a0823160e01b81523060048201526000916201000090046001600160a01b0316906370a0823190602401602060405180830381865afa158015612852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128769190614e00565b9050808211612883575050565b600660009054906101000a90046001600160a01b03166001600160a01b0316639af2e6356040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fa9190614dde565b61291757604051635f842b9960e11b815260040160405180910390fd5b60035460009061294b9061293890600160b01b900461ffff16612710614e5e565b84612941611ce7565b610f769190614e2f565b905060008261295a8386614e46565b6129649190614e2f565b6006546040516319d1885d60e31b8152600481018390529192506001600160a01b03169063ce8c42e890602401600060405180830381600087803b1580156129ab57600080fd5b505af11580156129bf573d6000803e3d6000fd5b505050507ff7e72e2f53a982a67fc999c00edfd87a94bdf99e5031c74851276cfd65b0bd29816040516129f491815260200190565b60405180910390a150505050565b6040516001600160a01b038316602482015260448101829052610a809084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161254f565b80516001600160a01b039081166000908152602081905260409020541615612ab55760405162461bcd60e51b815260206004820152601d60248201527f746f6b656e20616c7265616479206861732061207377617020706f6f6c0000006044820152606401610d2e565b6003546201000090046001600160a01b03166001600160a01b031681602001516001600160a01b031663c661065783606001516fffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401612b1891815260200190565b602060405180830381865afa158015612b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b599190614dc1565b6001600160a01b031614612bd55760405162461bcd60e51b815260206004820152602c60248201527f5f756e6465726c79696e674920646f6573206e6f74206d6174636820756e646560448201527f726c79696e6720746f6b656e00000000000000000000000000000000000000006064820152608401610d2e565b600081600001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3d9190614e81565b60ff1690506000612c5d6003546001600160a01b03620100009091041690565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cbe9190614e81565b6040805160a0810182526020808701516001600160a01b03908116835260ff8781168385019081529581168486018181528a870151600f90810b60608089019182528d015190910b608088019081528c5186166000908152968790529790952095518654985191518416600160a81b027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff92909416600160a01b027fffffffffffffffffffffff00000000000000000000000000000000000000000090991694169390931796909617919091161782555191516fffffffffffffffffffffffffffffffff908116600160801b029216919091176001909101559050612ddf612dd56003546001600160a01b03620100009091041690565b8460200151613afc565b612df183600001518460200151613afc565b82602001516001600160a01b031683600001516001600160a01b03167f1576b5fcfa863788d9ef6558cab7aa68d4b48c44eb7bacaf1a8ac6d6b9d26f9485604001518660600151604051612e55929190600f92830b8152910b602082015260400190565b60405180910390a3505050565b612e6a613b8d565b6003805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000612710612ec761ffff841685614ea4565b6125ad9190614ec3565b612ed9612f4a565b6003805461ff0019166101001790557f92493a2527e1a0e4214d0f98b1bedbdc2b53ef81ee4578756108fef0deff09ee612e973390565b612f18613bdf565b6003805461ff00191690557fc47f9c912614e04aeb80c7e6cdc73c0f4368cde4bf42df3b26ad96b898913c7d33612e97565b600354610100900460ff1615610f3c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a20457869745061757365640000000000000000000000006044820152606401610d2e565b6005546000612faf611ca4565b9050600085815b8181101561301957612ffd898983818110612fd357612fd3614ee5565b9050602002013586868d60008c8c88818110612ff157612ff1614ee5565b90506020020135613c36565b6130079084614e46565b925061301281614efb565b9050612fb6565b5061302382612803565b600354613040906201000090046001600160a01b03168a84612a02565b505050505050505050565b6005546000613058611ca4565b9050600084815b818110156130de576000600960008a8a8581811061307f5761307f614ee5565b9050602002013581526020019081526020016000206000015490506130c08989848181106130af576130af614ee5565b9050602002013587878d8b86613c36565b6130ca9085614e46565b935050806130d790614efb565b905061305f565b506130e882612803565b600354613105906201000090046001600160a01b03168984612a02565b5050505050505050565b61311761314c565b6003805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612e973390565b60035460ff1615610f3c5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610d2e565b606060408201356131dc576040517fab59997c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166132176040840160208501614f16565b67ffffffffffffffff161080613248575062dd7c0061323c6040840160208501614f16565b67ffffffffffffffff16115b1561326657604051636235acd960e01b815260040160405180910390fd5b60036132756080840184614f40565b905010156132af576040517f3867858900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006132bc600c54613f98565b905060006132c8611ca4565b905080821115613304576040517f08063cab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61331f3361331560208701876149e7565b86604001356134c7565b600061334061333160208701876149e7565b86604001358760a001356135ff565b90506000426133556040880160208901614f16565b61335f9190614f87565b905061338783838361337460608b018b614fb3565b61338160808d018d614f40565b8e613fb7565b979650505050505050565b600083158061339f575082155b806133a8575081155b156133b5575060006125ad565b826133c08584614ea4565b6125aa9190614ec3565b6000836133d9575060006125ad565b826133f7576133f0670de0b6b3a764000085614ea4565b90506125ad565b8161342e576040517ff91b6e7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816133c08486614ea4565b600083815b818160ff1610156134b357600087878360ff1681811061346057613460614ee5565b905060200201359050600086868460ff1681811061348057613480614ee5565b9050602002013590506134948a83836141f9565b61349e8186614e46565b94505050806134ac90614ffd565b905061343e565b506134be87836143d6565b50505050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190614e00565b90506135496001600160a01b03841685308561443c565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015613590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b49190614e00565b90506135c08383614e46565b81146135f8576040517f2a25a38b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60008061361b6003546001600160a01b03620100009091041690565b9050806001600160a01b0316856001600160a01b0316141561364057839150506125ad565b6001600160a01b03808616600090815260208190526040902080549091166136aa5760405162461bcd60e51b815260206004820152601660248201527f6e6f6e2d6578697374696e67207377617020706f6f6c000000000000000000006044820152606401610d2e565b80546000906136cf90879060ff600160a01b8204811691600160a81b90041688614493565b825460018401546040517fa6417ed6000000000000000000000000000000000000000000000000000000008152600f82810b6004830152600160801b90920490910b602482015260448101899052606481018390529192506001600160a01b03169063a6417ed6906084016020604051808303816000875af1158015613759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377d9190614e00565b9350826001600160a01b0316876001600160a01b03167ffa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe23588876040516137cd929190918252602082015260400190565b60405180910390a35050509392505050565b600081815b818160ff16101561384f57600085858360ff1681811061380657613806614ee5565b602090810292909201356000818152600990935260409092205491925061383090508883836141f9565b61383a8186614e46565b945050508061384890614ffd565b90506137e4565b506135f885836143d6565b60006138af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661259b9092919063ffffffff16565b805190915015610a8057808060200190518101906138cd9190614dde565b610a805760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d2e565b6060824710156139b75760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d2e565b6001600160a01b0385163b613a0e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d2e565b600080866001600160a01b03168587604051613a2a9190615049565b60006040518083038185875af1925050503d8060008114613a67576040519150601f19603f3d011682016040523d82523d6000602084013e613a6c565b606091505b50915091506133878282866144de565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16610d4157613aba816001600160a01b03166014614517565b613ac5836020614517565b604051602001613ad6929190615065565b60408051601f198184030181529082905262461bcd60e51b8252610d2e91600401615112565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa158015613b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b709190614e00565b905080610a8057610a806001600160a01b0384168360001961241e565b60035460ff16610f3c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610d2e565b600354610100900460ff16610f3c5760405162461bcd60e51b815260206004820152601860248201527f5061757361626c653a206e6f74204578697450617573656400000000000000006044820152606401610d2e565b6000868152600960205260408120600101546001600160a01b03163314613c89576040517fff40736100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008781526009602090815260408083208151608081018352815481526001808301546001600160a01b039081168387015260028401541682850181905260039093015460608301908152928652600b85529483902083518085019094528054845290940154928201929092529051421015613d31576040517f0f6268c200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516001600160a01b0316613d75576040517fde8b700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151841115613d9757604051635bcd1de160e11b815260040160405180910390fd5b6000613da4858a8a6133ca565b82516020840151919250600091613dbb9088614ea4565b613dc59190614ec3565b905086158015613dd457508082115b15613e0b576040517f7df2e7ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81878015613e1857508183115b15613e205750805b6040808601516001600160a01b03166000908152600b6020529081206001018054839290613e4f908490614e2f565b90915550506040808601516001600160a01b03166000908152600b6020529081208054899290613e80908490614e2f565b925050819055508060056000828254613e999190614e2f565b9250508190555086600c6000828254613eb29190614e2f565b9091555050845187148015613efb5760008d81526009602052604081208181556001810180546001600160a01b0319908116909155600282018054909116905560030155613f1f565b60008d815260096020526040812080548a9290613f19908490614e2f565b90915550505b6000613f2c838e8e613392565b90508a6001600160a01b03168e7f14e79002ce0df3ba4381425c583d4c9984c7e2910d3e7e088377db997773153e858486604051613f7f9392919092835260208301919091521515604082015260600190565b60405180910390a39d9c50505050505050505050505050565b600f54600090613fad90839061ffff16612eb4565b610a549083614e2f565b6040805160a0810182526005548152602081018a90526000918101829052606081810183905260808201879052918667ffffffffffffffff811115613ffe57613ffe614a4d565b604051908082528060200260200182016040528015614027578160200160208202803683370190505b50905060005b82608001518110156141a157600089898381811061404d5761404d614ee5565b905060200281019061405f9190615125565b6140689061513b565b805190915061ffff166140a7576040517f4f287e5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516001600160a01b03166140eb576040517fd444696b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600185608001516140fe9190614e2f565b8314614116578151614111908e90612eb4565b614125565b6060850151614125908e614e2f565b905061413f87828e8589600001518a602001518f8f6146f8565b84848151811061415157614151614ee5565b6020908102919091010152815160408601805161416f9083906151fb565b61ffff1690525060608501805182919061418a908390614e46565b90525061419a9150829050614efb565b905061402d565b506141b5826040015161ffff166127101490565b6141eb576040517fd7b03e8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9a9950505050505050505050565b60008281526009602090815260409182902082516080810184528154815260018201546001600160a01b0390811693820184905260028301541693810193909352600301546060830152331461427b576040517f5040aaa300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42816060015111156142b9576040517f4cf1715e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408101516001600160a01b0316156142fe576040517f6f15ccf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182111561432057604051635bcd1de160e11b815260040160405180910390fd5b80516040805184815291841460208301819052916001600160a01b0387169186917f8bb6f71206f2ec5e5a42539a0d677bb7e48844b6cefdad5d7139fd68568d7299910160405180910390a38061439b576000848152600960205260408120805485929061438f908490614e2f565b90915550505050505050565b50505060009081526009602052604081208181556001810180546001600160a01b031990811690915560028201805490911690556003015550565b6143de611ce7565b8111156143fe57604051635f842b9960e11b815260040160405180910390fd5b80600460008282546144109190614e2f565b9091555061441f905081612803565b600354610d41906201000090046001600160a01b03168383612a02565b6040516001600160a01b038085166024830152831660448201526064810182905261448d9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161254f565b50505050565b60006144a084600a6152fc565b6144ac90612710614ea4565b6144b784600a6152fc565b6144c18488614ea4565b6144cb9190614ea4565b6144d59190614ec3565b95945050505050565b606083156144ed5750816125ad565b8251156144fd5782518084602001fd5b8160405162461bcd60e51b8152600401610d2e9190615112565b60606000614526836002614ea4565b614531906002614e46565b67ffffffffffffffff81111561454957614549614a4d565b6040519080825280601f01601f191660200182016040528015614573576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000816000815181106145aa576145aa614ee5565b60200101906001600160f81b031916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106145f5576145f5614ee5565b60200101906001600160f81b031916908160001a9053506000614619846002614ea4565b614624906001614e46565b90505b60018111156146a9577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061466557614665614ee5565b1a60f81b82828151811061467b5761467b614ee5565b60200101906001600160f81b031916908160001a90535060049490941c936146a28161530b565b9050614627565b5083156125ad5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610d2e565b6000614708600a80546001019055565b600060405180606001604052806147208b89896133ca565b815260200188602001516001600160a01b03168152602001614741600a5490565b9052602080820180516001600160a01b039081166000908152600b90935260408084206001015492519091168352909120549192509061478b9061478490613f98565b88886133ca565b11156147c3576040517fb010931500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020808301516001600160a01b03166000908152600b9091526040812060010180549091906147f5908490614e46565b90915550506020808201516001600160a01b03166000908152600b9091526040812080548b9290614827908490614e46565b9091555050805160058054600090614840908490614e46565b9250508190555088600c60008282546148599190614e46565b9250508190555060405180608001604052808a8152602001336001600160a01b0316815260200182602001516001600160a01b031681526020018967ffffffffffffffff1681525060096000836040015181526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015590505086602001516001600160a01b0316336001600160a01b031682604001517fb26a67c96199378f459c394f9a442f1a94d19837d1ac17c14e3d6366d98223088d8d866000015187602001518f8f604001518d8d60405161498f989796959493929190615322565b60405180910390a4604001519998505050505050505050565b6000602082840312156149ba57600080fd5b81356001600160e01b0319811681146125ad57600080fd5b6001600160a01b0381168114610d9d57600080fd5b6000602082840312156149f957600080fd5b81356125ad816149d2565b600060208284031215614a1657600080fd5b5035919050565b60008060408385031215614a3057600080fd5b823591506020830135614a42816149d2565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715614a8657614a86614a4d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ab557614ab5614a4d565b604052919050565b8035600f81900b8114614acf57600080fd5b919050565b600060808284031215614ae657600080fd5b6040516080810181811067ffffffffffffffff82111715614b0957614b09614a4d565b6040528235614b17816149d2565b81526020830135614b27816149d2565b6020820152614b3860408401614abd565b6040820152614b4960608401614abd565b60608201529392505050565b803561ffff81168114614acf57600080fd5b600060208284031215614b7957600080fd5b6125ad82614b55565b60008083601f840112614b9457600080fd5b50813567ffffffffffffffff811115614bac57600080fd5b6020830191508360208260051b8501011115614bc757600080fd5b9250929050565b600080600080600060608688031215614be657600080fd5b8535614bf1816149d2565b9450602086013567ffffffffffffffff80821115614c0e57600080fd5b614c1a89838a01614b82565b90965094506040880135915080821115614c3357600080fd5b50614c4088828901614b82565b969995985093965092949392505050565b600080600060408486031215614c6657600080fd5b8335614c71816149d2565b9250602084013567ffffffffffffffff811115614c8d57600080fd5b614c9986828701614b82565b9497909650939450505050565b600060c08284031215614cb857600080fd5b50919050565b600060208284031215614cd057600080fd5b813567ffffffffffffffff811115614ce757600080fd5b614cf384828501614ca6565b949350505050565b6020808252825182820181905260009190848201906040850190845b81811015614d3357835183529284019291840191600101614d17565b50909695505050505050565b60008060408385031215614d5257600080fd5b82359150602083013567ffffffffffffffff811115614d7057600080fd5b614d7c85828601614ca6565b9150509250929050565b60008060008060808587031215614d9c57600080fd5b8435614da7816149d2565b966020860135965060408601359560600135945092505050565b600060208284031215614dd357600080fd5b81516125ad816149d2565b600060208284031215614df057600080fd5b815180151581146125ad57600080fd5b600060208284031215614e1257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600082821015614e4157614e41614e19565b500390565b60008219821115614e5957614e59614e19565b500190565b600061ffff83811690831681811015614e7957614e79614e19565b039392505050565b600060208284031215614e9357600080fd5b815160ff811681146125ad57600080fd5b6000816000190483118215151615614ebe57614ebe614e19565b500290565b600082614ee057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b6000600019821415614f0f57614f0f614e19565b5060010190565b600060208284031215614f2857600080fd5b813567ffffffffffffffff811681146125ad57600080fd5b6000808335601e19843603018112614f5757600080fd5b83018035915067ffffffffffffffff821115614f7257600080fd5b602001915036819003821315614bc757600080fd5b600067ffffffffffffffff808316818516808303821115614faa57614faa614e19565b01949350505050565b6000808335601e19843603018112614fca57600080fd5b83018035915067ffffffffffffffff821115614fe557600080fd5b6020019150600581901b3603821315614bc757600080fd5b600060ff821660ff81141561501457615014614e19565b60010192915050565b60005b83811015615038578181015183820152602001615020565b8381111561448d5750506000910152565b6000825161505b81846020870161501d565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161509d81601785016020880161501d565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516150da81602884016020880161501d565b01602801949350505050565b600081518084526150fe81602086016020860161501d565b601f01601f19169290920160200192915050565b6020815260006125ad60208301846150e6565b60008235605e1983360301811261505b57600080fd5b60006060823603121561514d57600080fd5b615155614a63565b61515e83614b55565b815260208084013561516f816149d2565b82820152604084013567ffffffffffffffff8082111561518e57600080fd5b9085019036601f8301126151a157600080fd5b8135818111156151b3576151b3614a4d565b6151c5601f8201601f19168501614a8c565b915080825236848285010111156151db57600080fd5b808484018584013760009082019093019290925250604082015292915050565b600061ffff808316818516808303821115614faa57614faa614e19565b600181815b8085111561525357816000190482111561523957615239614e19565b8085161561524657918102915b93841c939080029061521d565b509250929050565b60008261526a57506001610a54565b8161527757506000610a54565b816001811461528d5760028114615297576152b3565b6001915050610a54565b60ff8411156152a8576152a8614e19565b50506001821b610a54565b5060208310610133831016604e8410600b84101617156152d6575081810a610a54565b6152e08383615218565b80600019048211156152f4576152f4614e19565b029392505050565b60006125ad60ff84168361525b565b60008161531a5761531a614e19565b506000190190565b8881528760208201528660408201526001600160a01b038616606082015267ffffffffffffffff8516608082015260e060a0820152600061536660e08301866150e6565b82810360c0840152838152838560208301376000602085830101526020601f19601f860116820101915050999850505050505050505056fea264697066735822122067db7a707d6e781088d1ec391c13c78844a6370488f1a5eca731a1efb57d8d0064736f6c634300080a00330000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0000000000000000000000000000000000000000000000000000000000076a7000000000000000000000000000000000000000000000000000000000000002328000000000000000000000000035f210e5d14054e8ae5a6cfa76d643aa200d56e00000000000000000000000084f67f75daf6d57aef500e0c85c77b7b3bbc92a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106103af5760003560e01c80638456cb59116101f4578063c0ddb6921161011a578063df6f9ba7116100ad578063f5eb42dc1161007c578063f5eb42dc14610951578063f62898871461097d578063f78797c0146109a4578063fd6e9217146109cd57600080fd5b8063df6f9ba71461090f578063e4020fdf14610922578063eb0ebfbc14610935578063f0f442601461093e57600080fd5b8063cd0d9ba8116100e9578063cd0d9ba8146108c1578063cda2695a146108d4578063d547741f146108e7578063d9db2b77146108fa57600080fd5b8063c0ddb69214610877578063c2d794441461087f578063c70920bc146108a6578063cd00dd41146108ae57600080fd5b8063a217fddf11610192578063b5106add11610161578063b5106add14610816578063b59a40cb14610829578063bba97d3314610849578063bd2e3ecd1461061857600080fd5b8063a217fddf14610779578063a8c62e7614610781578063abaa9d7014610794578063b02c43d0146107a457600080fd5b80639816f473116101ce5780639816f47314610732578063999927df14610749578063a164c25d1461075c578063a1ac20eb1461076657600080fd5b80638456cb591461065b5780638cad7fbe1461066357806391d14854146106f957600080fd5b80634e813ac4116102d957806361e20a1c1161027757806376490b561161024657806376490b56146106185780637e2cba6f146106225780637e4b8da0146106355780638293744b1461064857600080fd5b806361e20a1c146105755780636e7007e61461059e5780636f307dc3146105bf57806373ae54b5146105d857600080fd5b80635c975abb116102b35780635c975abb1461052f5780635cb0d4061461053a5780635e8486551461054257806361d027b31461054a57600080fd5b80634e813ac41461050c5780634fc78d6814610514578063563233f61461051c57600080fd5b8063364bc15a116103515780633ba52fc6116103205780633ba52fc6146104e05780633f383236146104e85780633f4ba83a146104fb5780634b1533b21461050357600080fd5b8063364bc15a1461048a57806336568abe146104b15780633a98ef39146104c45780633b7d0946146104cd57600080fd5b806319d3ee3d1161038d57806319d3ee3d14610435578063248a9ca31461043e5780632f2ff15d1461046257806333a100ca1461047757600080fd5b806301ffc9a7146103b45780631325d5f1146103dc57806313f6686d146103f9575b600080fd5b6103c76103c23660046149a8565b6109e2565b60405190151581526020015b60405180910390f35b6103eb670de0b6b3a764000081565b6040519081526020016103d3565b6104206104073660046149e7565b600b602052600090815260409020805460019091015482565b604080519283526020830191909152016103d3565b6103eb600e5481565b6103eb61044c366004614a04565b6000908152600160208190526040909120015490565b610475610470366004614a1d565b610a5a565b005b6104756104853660046149e7565b610a85565b6103eb7ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab81565b6104756104bf366004614a1d565b610cb4565b6103eb60055481565b6104756104db3660046149e7565b610d45565b610475610da0565b6104756104f6366004614ad4565b610e8d565b610475610ee5565b6103eb600c5481565b610420610f3e565b610475610ffb565b61047561052a366004614b67565b6112ba565b60035460ff166103c7565b6104756113ba565b6104756113cd565b600d5461055d906001600160a01b031681565b6040516001600160a01b0390911681526020016103d3565b6103eb6105833660046149e7565b6001600160a01b03166000908152600b602052604090205490565b600f546105ac9061ffff1681565b60405161ffff90911681526020016103d3565b60035461055d906201000090046001600160a01b031681565b6105ff7f000000000000000000000000000000000000000000000000000000000076a70081565b60405167ffffffffffffffff90911681526020016103d3565b6105ff62dd7c0081565b610475610630366004614b67565b6113e0565b610475610643366004614bce565b6114b3565b610475610656366004614c51565b611551565b610475611630565b6106ba6106713660046149e7565b600060208190529081526040902080546001909101546001600160a01b0382169160ff600160a01b8204811692600160a81b9092041690600f81810b91600160801b9004900b85565b604080516001600160a01b03909616865260ff94851660208701529390921692840192909252600f91820b6060840152900b608082015260a0016103d3565b6103c7610707366004614a1d565b60009182526001602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6003546201000090046001600160a01b031661055d565b6104756107573660046149e7565b611687565b6105ff6212750081565b610475610774366004614b67565b61185a565b6103eb600081565b60065461055d906001600160a01b031681565b600354610100900460ff166103c7565b6107e66107b2366004614a04565b600960205260009081526040902080546001820154600283015460039093015491926001600160a01b039182169291169084565b6040516103d394939291909384526001600160a01b03928316602085015291166040830152606082015260800190565b6104756108243660046149e7565b61195c565b61083c610837366004614cbe565b611b40565b6040516103d39190614cfb565b61085c6108573660046149e7565b611be5565b604080519384526020840192909252908201526060016103d3565b6103eb611ca4565b6103eb7f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a81565b6103eb611ce7565b6104756108bc366004614bce565b611e63565b61083c6108cf366004614d3f565b611ef5565b6104756108e2366004614d86565b611faf565b6104756108f5366004614a1d565b6121f5565b600d546105ac90600160a01b900461ffff1681565b61047561091d366004614c51565b61221b565b610475610930366004614c51565b6122ad565b6103eb60045481565b61047561094c3660046149e7565b61233d565b6103eb61095f3660046149e7565b6001600160a01b03166000908152600b602052604090206001015490565b6103eb7ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf60309581565b61055d6109b2366004614a04565b6008602052600090815260409020546001600160a01b031681565b6003546105ac90600160b01b900461ffff1681565b60006001600160e01b031982167f21d982ed000000000000000000000000000000000000000000000000000000001480610a4557506001600160e01b031982167f0fae047800000000000000000000000000000000000000000000000000000000145b80610a545750610a54826125b4565b92915050565b60008281526001602081905260409091200154610a768161261b565b610a808383612625565b505050565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff16610ad457604051631e15456f60e11b815260040160405180910390fd5b6001600160a01b038116610afb57604051634f08b3f360e11b815260040160405180910390fd5b306001600160a01b0316816001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b679190614dc1565b6001600160a01b031614610ba7576040517f0251bab500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546001600160a01b031615801590610c335750600660009054906101000a90046001600160a01b03166001600160a01b0316635be9b2d36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c339190614dde565b15610c6a576040517fd28a9fdb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600680546001600160a01b0319166001600160a01b0383169081179091556040517f4da9c22c924692646a21cf1f423781ae3285198dc22e8a6912835d3272b90b3c90600090a250565b6001600160a01b0381163314610d375760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b610d4182826126ac565b5050565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff16610d9457604051631bacfc6960e01b815260040160405180910390fd5b610d9d8161272f565b50565b3360009081527f10c15aae13326e9b33c92ffbb94efb7492c500f0cca324caca9bd1aca194ed18602052604090205460ff16610def57604051637660f80560e11b815260040160405180910390fd5b600e5480610e29576040517f0a33934000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600e55610e3781612803565b6040518181527fb7eeacba6b133788365610e83d3f130d07b6ef6e78877961f25b3f61fcba07529060200160405180910390a1600d54600354610d9d916001600160a01b03620100009092048216911683612a02565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff16610edc57604051631bacfc6960e01b815260040160405180910390fd5b610d9d81612a4b565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff16610f3457604051631bacfc6960e01b815260040160405180910390fd5b610f3c612e62565b565b60065460009081906001600160a01b0316610f5c5750600091829150565b600354610f7c90600160b01b900461ffff16610f76611ce7565b90612eb4565b9150600660009054906101000a90046001600160a01b03166001600160a01b0316634ad0b6846040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fd1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff59190614e00565b90509091565b3360009081527f10c15aae13326e9b33c92ffbb94efb7492c500f0cca324caca9bd1aca194ed18602052604090205460ff1661104a57604051637660f80560e11b815260040160405180910390fd5b6006546001600160a01b031661107357604051634f08b3f360e11b815260040160405180910390fd5b60008061107e610f3e565b91509150808214156110bc576040517ff096593000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b818111156111af5760006110d08383614e2f565b90507f0000000000000000000000000000000000000000000000008ac7230489e8000081101561111357604051630e33bdb760e11b815260040160405180910390fd5b6006546040516319d1885d60e31b8152600481018390526001600160a01b039091169063ce8c42e890602401600060405180830381600087803b15801561115957600080fd5b505af115801561116d573d6000803e3d6000fd5b505050507ff7e72e2f53a982a67fc999c00edfd87a94bdf99e5031c74851276cfd65b0bd29816040516111a291815260200190565b60405180910390a1505050565b60006111bb8284614e2f565b90507f0000000000000000000000000000000000000000000000008ac7230489e800008110156111fe57604051630e33bdb760e11b815260040160405180910390fd5b600654600354611221916001600160a01b03620100009092048216911683612a02565b600660009054906101000a90046001600160a01b03166001600160a01b031663e8b5e51f6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561127157600080fd5b505af1158015611285573d6000803e3d6000fd5b505050507fac9f7997c30b6a3cc9c74953898b5de154359339c7ec0d6d70ceb98e55db1a4b816040516111a291815260200190565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff1661130957604051631e15456f60e11b815260040160405180910390fd5b61ffff81166127101015611349576040517fd25b1e4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff16600160a01b61ffff8416908102919091179091556040519081527f16de0efbdf16c568a60b65978ed774bba4e0c179de55ab8f639527e41fd0c861906020015b60405180910390a150565b60006113c58161261b565b610d9d612ed1565b60006113d88161261b565b610d9d612f10565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff1661142f57604051631e15456f60e11b815260040160405180910390fd5b61ffff8116612710101561146f576040517f1d05623100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600f805461ffff191661ffff83169081179091556040519081527f5b9aa28fc994f782b33ebebd9947795b5bc59a54203466433eac5f8d9e819400906020016113af565b6002805414156115055760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611511612f4a565b6001600160a01b0385166115385760405163f95106ab60e01b815260040160405180910390fd5b6115458585858585612fa2565b50506001600255505050565b6002805414156115a35760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b600280556115af612f4a565b6001600160a01b0383166115d65760405163f95106ab60e01b815260040160405180910390fd5b6115de611ca4565b600c541115611619576040517f0bdd660c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611626838383600061304b565b5050600160025550565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff1661167f57604051631bacfc6960e01b815260040160405180910390fd5b610f3c61310f565b6002805414156116d95760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b600280556116e5612f4a565b6001600160a01b03811661170c5760405163f95106ab60e01b815260040160405180910390fd5b600080600061171a33611be5565b925092509250826000141561175b576040517f58367fe100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611765611ca4565b90506000600554905082600e60008282546117809190614e46565b9091555061178f905085612803565b6003546117ac906201000090046001600160a01b03168787612a02565b336000908152600b6020526040812060010180548692906117ce908490614e2f565b9250508190555083600560008282546117e79190614e2f565b90915550506040805133815260208101879052908101859052606081018490526080810183905260a081018290526001600160a01b038716907f4344accc2a634cf29195bba6fa3d939e3415ecd1ca5c57b322bcf81f920979c89060c00160405180910390a25050600160025550505050565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff166118a957604051631e15456f60e11b815260040160405180910390fd5b61ffff811661271010156118e9576040517f870e44a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60405161ffff821681527f40775ca73a6e168d23747bc0200694cf7c99ad2db624d04c095cb59899011a569060200160405180910390a16003805461ffff909216600160b01b027fffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff166119ab57604051631bacfc6960e01b815260040160405180910390fd5b6001600160a01b0381166119eb576040517f30c9889300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038116331415611a2e576040517f25499f7e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a39600082612625565b611a637ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab82612625565b611a8d7ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf60309582612625565b611ab77f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a82612625565b611ac26000336126ac565b611aec7ffc8737ab85eb45125971625a9ebdb75cc78e01d5c1fa80c4c6e5203f47bc4fab336126ac565b611b167ffaf9b26485088dee58863e57c46603d6cdcbadc7475ac6d8910fab0ecf603095336126ac565b610d9d7f1597bc5e34ff090612f53164e4e642d2ab4fc78bffe19ed1b602a0d12559561a336126ac565b6060600280541415611b945760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611ba061314c565b600754611bae816001614e46565b600755600081815260086020526040902080546001600160a01b03191633179055611bd9818461319f565b60016002559392505050565b6001600160a01b0381166000908152600b6020526040812080546001909101548291829182611c12611ca4565b90506000611c238360055484613392565b9050838111611c4057600080600096509650965050505050611c9d565b6000611c4c8583614e2f565b9050611c5b81600554856133ca565b96506000611c6c8860055486613392565b600d54909150611c88908290600160a01b900461ffff16612eb4565b9650611c948782614e2f565b98505050505050505b9193909250565b600080611caf611ce7565b90506000600e54600454611cc39190614e46565b905081811115611cd65760009250505090565b611ce08183614e2f565b9250505090565b6006546000906001600160a01b031615611df257600660009054906101000a90046001600160a01b03166001600160a01b0316634ad0b6846040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d4e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d729190614e00565b6003546040516370a0823160e01b8152306004820152620100009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611dbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611de39190614e00565b611ded9190614e46565b905090565b6003546040516370a0823160e01b8152306004820152620100009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611e3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ded9190614e00565b600280541415611eb55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611ec1612f4a565b6001600160a01b038516611ee85760405163f95106ab60e01b815260040160405180910390fd5b6115458585858585613439565b6060600280541415611f495760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055611f5561314c565b6000838152600860205260409020546001600160a01b03163314611fa5576040517f9049b68600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611bd9838361319f565b6002805414156120015760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b600280553360009081527f27365024d84ecf053ef4d13025b66be161b03e90a7fc7ff54f74d5533a9f857e602052604090205460ff1661206d576040517f9aff7af000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61207561314c565b826120ac576040517ff712805800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b621275008210806120bf575062dd7c0082115b156120dd57604051636235acd960e01b815260040160405180910390fd5b60006120e94284614e46565b90506120f9600a80546001019055565b6000612104600a5490565b90506121113387876134c7565b600061211e8787866135ff565b604080516080810182528281523360208083019182526000838501818152606085018a815289835260099093529481209351845591516001840180546001600160a01b03199081166001600160a01b0393841617909155945160028501805490961691161790935591516003909101556004805492935083929091906121a5908490614e46565b90915550506040805182815260208101859052339184917f7ca3497675c6d3ec00b1edc13b8e0b06169ee96a663ab25a74af7da53378f09e910160405180910390a3505060016002555050505050565b600082815260016020819052604090912001546122118161261b565b610a8083836126ac565b60028054141561226d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b60028055612279612f4a565b6001600160a01b0383166122a05760405163f95106ab60e01b815260040160405180910390fd5b611626838383600161304b565b6002805414156122ff5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610d2e565b6002805561230b612f4a565b6001600160a01b0383166123325760405163f95106ab60e01b815260040160405180910390fd5b6116268383836137df565b3360009081527f473683a5a3e156e4e3a6c3a7a6d9e3d4a58f9392a3bba04b84ad6221b3f7f356602052604090205460ff1661238c57604051631e15456f60e11b815260040160405180910390fd5b6001600160a01b0381166123cc576040517f6b5e63d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d80546001600160a01b0319166001600160a01b0383169081179091556040517f7dae230f18360d76a040c81f050aa14eb9d6dc7901b20fc5d855e2a20fe814d190600090a250565b612710101590565b8015806124985750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612472573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124969190614e00565b155b61250a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401610d2e565b6040516001600160a01b038316602482015260448101829052610a809084907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b03199093169290921790915261385a565b60606125aa848460008561393f565b90505b9392505050565b60006001600160e01b031982167f7965db0b000000000000000000000000000000000000000000000000000000001480610a5457507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610a54565b610d9d8133613a7c565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16610d415760008281526001602081815260408084206001600160a01b0386168086529252808420805460ff19169093179092559051339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff1615610d415760008281526001602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b03818116600090815260208190526040902054166127965760405162461bcd60e51b815260206004820152601360248201527f706f6f6c20646f6573206e6f74206578697374000000000000000000000000006044820152606401610d2e565b6001600160a01b03811660008181526020819052604080822080547fffffffffffffffffffff00000000000000000000000000000000000000000000168155600101829055517f94be23730c4398d20227f4e457cf92307b13e5956f2a958e2e368ad44e2f826b9190a250565b6003546040516370a0823160e01b81523060048201526000916201000090046001600160a01b0316906370a0823190602401602060405180830381865afa158015612852573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128769190614e00565b9050808211612883575050565b600660009054906101000a90046001600160a01b03166001600160a01b0316639af2e6356040518163ffffffff1660e01b8152600401602060405180830381865afa1580156128d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fa9190614dde565b61291757604051635f842b9960e11b815260040160405180910390fd5b60035460009061294b9061293890600160b01b900461ffff16612710614e5e565b84612941611ce7565b610f769190614e2f565b905060008261295a8386614e46565b6129649190614e2f565b6006546040516319d1885d60e31b8152600481018390529192506001600160a01b03169063ce8c42e890602401600060405180830381600087803b1580156129ab57600080fd5b505af11580156129bf573d6000803e3d6000fd5b505050507ff7e72e2f53a982a67fc999c00edfd87a94bdf99e5031c74851276cfd65b0bd29816040516129f491815260200190565b60405180910390a150505050565b6040516001600160a01b038316602482015260448101829052610a809084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161254f565b80516001600160a01b039081166000908152602081905260409020541615612ab55760405162461bcd60e51b815260206004820152601d60248201527f746f6b656e20616c7265616479206861732061207377617020706f6f6c0000006044820152606401610d2e565b6003546201000090046001600160a01b03166001600160a01b031681602001516001600160a01b031663c661065783606001516fffffffffffffffffffffffffffffffff166040518263ffffffff1660e01b8152600401612b1891815260200190565b602060405180830381865afa158015612b35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b599190614dc1565b6001600160a01b031614612bd55760405162461bcd60e51b815260206004820152602c60248201527f5f756e6465726c79696e674920646f6573206e6f74206d6174636820756e646560448201527f726c79696e6720746f6b656e00000000000000000000000000000000000000006064820152608401610d2e565b600081600001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3d9190614e81565b60ff1690506000612c5d6003546001600160a01b03620100009091041690565b6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cbe9190614e81565b6040805160a0810182526020808701516001600160a01b03908116835260ff8781168385019081529581168486018181528a870151600f90810b60608089019182528d015190910b608088019081528c5186166000908152968790529790952095518654985191518416600160a81b027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff92909416600160a01b027fffffffffffffffffffffff00000000000000000000000000000000000000000090991694169390931796909617919091161782555191516fffffffffffffffffffffffffffffffff908116600160801b029216919091176001909101559050612ddf612dd56003546001600160a01b03620100009091041690565b8460200151613afc565b612df183600001518460200151613afc565b82602001516001600160a01b031683600001516001600160a01b03167f1576b5fcfa863788d9ef6558cab7aa68d4b48c44eb7bacaf1a8ac6d6b9d26f9485604001518660600151604051612e55929190600f92830b8152910b602082015260400190565b60405180910390a3505050565b612e6a613b8d565b6003805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000612710612ec761ffff841685614ea4565b6125ad9190614ec3565b612ed9612f4a565b6003805461ff0019166101001790557f92493a2527e1a0e4214d0f98b1bedbdc2b53ef81ee4578756108fef0deff09ee612e973390565b612f18613bdf565b6003805461ff00191690557fc47f9c912614e04aeb80c7e6cdc73c0f4368cde4bf42df3b26ad96b898913c7d33612e97565b600354610100900460ff1615610f3c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a20457869745061757365640000000000000000000000006044820152606401610d2e565b6005546000612faf611ca4565b9050600085815b8181101561301957612ffd898983818110612fd357612fd3614ee5565b9050602002013586868d60008c8c88818110612ff157612ff1614ee5565b90506020020135613c36565b6130079084614e46565b925061301281614efb565b9050612fb6565b5061302382612803565b600354613040906201000090046001600160a01b03168a84612a02565b505050505050505050565b6005546000613058611ca4565b9050600084815b818110156130de576000600960008a8a8581811061307f5761307f614ee5565b9050602002013581526020019081526020016000206000015490506130c08989848181106130af576130af614ee5565b9050602002013587878d8b86613c36565b6130ca9085614e46565b935050806130d790614efb565b905061305f565b506130e882612803565b600354613105906201000090046001600160a01b03168984612a02565b5050505050505050565b61311761314c565b6003805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612e973390565b60035460ff1615610f3c5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610d2e565b606060408201356131dc576040517fab59997c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000076a700166132176040840160208501614f16565b67ffffffffffffffff161080613248575062dd7c0061323c6040840160208501614f16565b67ffffffffffffffff16115b1561326657604051636235acd960e01b815260040160405180910390fd5b60036132756080840184614f40565b905010156132af576040517f3867858900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006132bc600c54613f98565b905060006132c8611ca4565b905080821115613304576040517f08063cab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61331f3361331560208701876149e7565b86604001356134c7565b600061334061333160208701876149e7565b86604001358760a001356135ff565b90506000426133556040880160208901614f16565b61335f9190614f87565b905061338783838361337460608b018b614fb3565b61338160808d018d614f40565b8e613fb7565b979650505050505050565b600083158061339f575082155b806133a8575081155b156133b5575060006125ad565b826133c08584614ea4565b6125aa9190614ec3565b6000836133d9575060006125ad565b826133f7576133f0670de0b6b3a764000085614ea4565b90506125ad565b8161342e576040517ff91b6e7b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816133c08486614ea4565b600083815b818160ff1610156134b357600087878360ff1681811061346057613460614ee5565b905060200201359050600086868460ff1681811061348057613480614ee5565b9050602002013590506134948a83836141f9565b61349e8186614e46565b94505050806134ac90614ffd565b905061343e565b506134be87836143d6565b50505050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561350e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135329190614e00565b90506135496001600160a01b03841685308561443c565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015613590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135b49190614e00565b90506135c08383614e46565b81146135f8576040517f2a25a38b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b60008061361b6003546001600160a01b03620100009091041690565b9050806001600160a01b0316856001600160a01b0316141561364057839150506125ad565b6001600160a01b03808616600090815260208190526040902080549091166136aa5760405162461bcd60e51b815260206004820152601660248201527f6e6f6e2d6578697374696e67207377617020706f6f6c000000000000000000006044820152606401610d2e565b80546000906136cf90879060ff600160a01b8204811691600160a81b90041688614493565b825460018401546040517fa6417ed6000000000000000000000000000000000000000000000000000000008152600f82810b6004830152600160801b90920490910b602482015260448101899052606481018390529192506001600160a01b03169063a6417ed6906084016020604051808303816000875af1158015613759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061377d9190614e00565b9350826001600160a01b0316876001600160a01b03167ffa2dda1cc1b86e41239702756b13effbc1a092b5c57e3ad320fbe4f3b13fe23588876040516137cd929190918252602082015260400190565b60405180910390a35050509392505050565b600081815b818160ff16101561384f57600085858360ff1681811061380657613806614ee5565b602090810292909201356000818152600990935260409092205491925061383090508883836141f9565b61383a8186614e46565b945050508061384890614ffd565b90506137e4565b506135f885836143d6565b60006138af826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661259b9092919063ffffffff16565b805190915015610a8057808060200190518101906138cd9190614dde565b610a805760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610d2e565b6060824710156139b75760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610d2e565b6001600160a01b0385163b613a0e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610d2e565b600080866001600160a01b03168587604051613a2a9190615049565b60006040518083038185875af1925050503d8060008114613a67576040519150601f19603f3d011682016040523d82523d6000602084013e613a6c565b606091505b50915091506133878282866144de565b60008281526001602090815260408083206001600160a01b038516845290915290205460ff16610d4157613aba816001600160a01b03166014614517565b613ac5836020614517565b604051602001613ad6929190615065565b60408051601f198184030181529082905262461bcd60e51b8252610d2e91600401615112565b604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa158015613b4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b709190614e00565b905080610a8057610a806001600160a01b0384168360001961241e565b60035460ff16610f3c5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610d2e565b600354610100900460ff16610f3c5760405162461bcd60e51b815260206004820152601860248201527f5061757361626c653a206e6f74204578697450617573656400000000000000006044820152606401610d2e565b6000868152600960205260408120600101546001600160a01b03163314613c89576040517fff40736100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008781526009602090815260408083208151608081018352815481526001808301546001600160a01b039081168387015260028401541682850181905260039093015460608301908152928652600b85529483902083518085019094528054845290940154928201929092529051421015613d31576040517f0f6268c200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408201516001600160a01b0316613d75576040517fde8b700400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151841115613d9757604051635bcd1de160e11b815260040160405180910390fd5b6000613da4858a8a6133ca565b82516020840151919250600091613dbb9088614ea4565b613dc59190614ec3565b905086158015613dd457508082115b15613e0b576040517f7df2e7ab00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81878015613e1857508183115b15613e205750805b6040808601516001600160a01b03166000908152600b6020529081206001018054839290613e4f908490614e2f565b90915550506040808601516001600160a01b03166000908152600b6020529081208054899290613e80908490614e2f565b925050819055508060056000828254613e999190614e2f565b9250508190555086600c6000828254613eb29190614e2f565b9091555050845187148015613efb5760008d81526009602052604081208181556001810180546001600160a01b0319908116909155600282018054909116905560030155613f1f565b60008d815260096020526040812080548a9290613f19908490614e2f565b90915550505b6000613f2c838e8e613392565b90508a6001600160a01b03168e7f14e79002ce0df3ba4381425c583d4c9984c7e2910d3e7e088377db997773153e858486604051613f7f9392919092835260208301919091521515604082015260600190565b60405180910390a39d9c50505050505050505050505050565b600f54600090613fad90839061ffff16612eb4565b610a549083614e2f565b6040805160a0810182526005548152602081018a90526000918101829052606081810183905260808201879052918667ffffffffffffffff811115613ffe57613ffe614a4d565b604051908082528060200260200182016040528015614027578160200160208202803683370190505b50905060005b82608001518110156141a157600089898381811061404d5761404d614ee5565b905060200281019061405f9190615125565b6140689061513b565b805190915061ffff166140a7576040517f4f287e5000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208101516001600160a01b03166140eb576040517fd444696b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600185608001516140fe9190614e2f565b8314614116578151614111908e90612eb4565b614125565b6060850151614125908e614e2f565b905061413f87828e8589600001518a602001518f8f6146f8565b84848151811061415157614151614ee5565b6020908102919091010152815160408601805161416f9083906151fb565b61ffff1690525060608501805182919061418a908390614e46565b90525061419a9150829050614efb565b905061402d565b506141b5826040015161ffff166127101490565b6141eb576040517fd7b03e8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9a9950505050505050505050565b60008281526009602090815260409182902082516080810184528154815260018201546001600160a01b0390811693820184905260028301541693810193909352600301546060830152331461427b576040517f5040aaa300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42816060015111156142b9576040517f4cf1715e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408101516001600160a01b0316156142fe576040517f6f15ccf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805182111561432057604051635bcd1de160e11b815260040160405180910390fd5b80516040805184815291841460208301819052916001600160a01b0387169186917f8bb6f71206f2ec5e5a42539a0d677bb7e48844b6cefdad5d7139fd68568d7299910160405180910390a38061439b576000848152600960205260408120805485929061438f908490614e2f565b90915550505050505050565b50505060009081526009602052604081208181556001810180546001600160a01b031990811690915560028201805490911690556003015550565b6143de611ce7565b8111156143fe57604051635f842b9960e11b815260040160405180910390fd5b80600460008282546144109190614e2f565b9091555061441f905081612803565b600354610d41906201000090046001600160a01b03168383612a02565b6040516001600160a01b038085166024830152831660448201526064810182905261448d9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161254f565b50505050565b60006144a084600a6152fc565b6144ac90612710614ea4565b6144b784600a6152fc565b6144c18488614ea4565b6144cb9190614ea4565b6144d59190614ec3565b95945050505050565b606083156144ed5750816125ad565b8251156144fd5782518084602001fd5b8160405162461bcd60e51b8152600401610d2e9190615112565b60606000614526836002614ea4565b614531906002614e46565b67ffffffffffffffff81111561454957614549614a4d565b6040519080825280601f01601f191660200182016040528015614573576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000816000815181106145aa576145aa614ee5565b60200101906001600160f81b031916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106145f5576145f5614ee5565b60200101906001600160f81b031916908160001a9053506000614619846002614ea4565b614624906001614e46565b90505b60018111156146a9577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061466557614665614ee5565b1a60f81b82828151811061467b5761467b614ee5565b60200101906001600160f81b031916908160001a90535060049490941c936146a28161530b565b9050614627565b5083156125ad5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610d2e565b6000614708600a80546001019055565b600060405180606001604052806147208b89896133ca565b815260200188602001516001600160a01b03168152602001614741600a5490565b9052602080820180516001600160a01b039081166000908152600b90935260408084206001015492519091168352909120549192509061478b9061478490613f98565b88886133ca565b11156147c3576040517fb010931500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80516020808301516001600160a01b03166000908152600b9091526040812060010180549091906147f5908490614e46565b90915550506020808201516001600160a01b03166000908152600b9091526040812080548b9290614827908490614e46565b9091555050805160058054600090614840908490614e46565b9250508190555088600c60008282546148599190614e46565b9250508190555060405180608001604052808a8152602001336001600160a01b0316815260200182602001516001600160a01b031681526020018967ffffffffffffffff1681525060096000836040015181526020019081526020016000206000820151816000015560208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506060820151816003015590505086602001516001600160a01b0316336001600160a01b031682604001517fb26a67c96199378f459c394f9a442f1a94d19837d1ac17c14e3d6366d98223088d8d866000015187602001518f8f604001518d8d60405161498f989796959493929190615322565b60405180910390a4604001519998505050505050505050565b6000602082840312156149ba57600080fd5b81356001600160e01b0319811681146125ad57600080fd5b6001600160a01b0381168114610d9d57600080fd5b6000602082840312156149f957600080fd5b81356125ad816149d2565b600060208284031215614a1657600080fd5b5035919050565b60008060408385031215614a3057600080fd5b823591506020830135614a42816149d2565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715614a8657614a86614a4d565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ab557614ab5614a4d565b604052919050565b8035600f81900b8114614acf57600080fd5b919050565b600060808284031215614ae657600080fd5b6040516080810181811067ffffffffffffffff82111715614b0957614b09614a4d565b6040528235614b17816149d2565b81526020830135614b27816149d2565b6020820152614b3860408401614abd565b6040820152614b4960608401614abd565b60608201529392505050565b803561ffff81168114614acf57600080fd5b600060208284031215614b7957600080fd5b6125ad82614b55565b60008083601f840112614b9457600080fd5b50813567ffffffffffffffff811115614bac57600080fd5b6020830191508360208260051b8501011115614bc757600080fd5b9250929050565b600080600080600060608688031215614be657600080fd5b8535614bf1816149d2565b9450602086013567ffffffffffffffff80821115614c0e57600080fd5b614c1a89838a01614b82565b90965094506040880135915080821115614c3357600080fd5b50614c4088828901614b82565b969995985093965092949392505050565b600080600060408486031215614c6657600080fd5b8335614c71816149d2565b9250602084013567ffffffffffffffff811115614c8d57600080fd5b614c9986828701614b82565b9497909650939450505050565b600060c08284031215614cb857600080fd5b50919050565b600060208284031215614cd057600080fd5b813567ffffffffffffffff811115614ce757600080fd5b614cf384828501614ca6565b949350505050565b6020808252825182820181905260009190848201906040850190845b81811015614d3357835183529284019291840191600101614d17565b50909695505050505050565b60008060408385031215614d5257600080fd5b82359150602083013567ffffffffffffffff811115614d7057600080fd5b614d7c85828601614ca6565b9150509250929050565b60008060008060808587031215614d9c57600080fd5b8435614da7816149d2565b966020860135965060408601359560600135945092505050565b600060208284031215614dd357600080fd5b81516125ad816149d2565b600060208284031215614df057600080fd5b815180151581146125ad57600080fd5b600060208284031215614e1257600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600082821015614e4157614e41614e19565b500390565b60008219821115614e5957614e59614e19565b500190565b600061ffff83811690831681811015614e7957614e79614e19565b039392505050565b600060208284031215614e9357600080fd5b815160ff811681146125ad57600080fd5b6000816000190483118215151615614ebe57614ebe614e19565b500290565b600082614ee057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b6000600019821415614f0f57614f0f614e19565b5060010190565b600060208284031215614f2857600080fd5b813567ffffffffffffffff811681146125ad57600080fd5b6000808335601e19843603018112614f5757600080fd5b83018035915067ffffffffffffffff821115614f7257600080fd5b602001915036819003821315614bc757600080fd5b600067ffffffffffffffff808316818516808303821115614faa57614faa614e19565b01949350505050565b6000808335601e19843603018112614fca57600080fd5b83018035915067ffffffffffffffff821115614fe557600080fd5b6020019150600581901b3603821315614bc757600080fd5b600060ff821660ff81141561501457615014614e19565b60010192915050565b60005b83811015615038578181015183820152602001615020565b8381111561448d5750506000910152565b6000825161505b81846020870161501d565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161509d81601785016020880161501d565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516150da81602884016020880161501d565b01602801949350505050565b600081518084526150fe81602086016020860161501d565b601f01601f19169290920160200192915050565b6020815260006125ad60208301846150e6565b60008235605e1983360301811261505b57600080fd5b60006060823603121561514d57600080fd5b615155614a63565b61515e83614b55565b815260208084013561516f816149d2565b82820152604084013567ffffffffffffffff8082111561518e57600080fd5b9085019036601f8301126151a157600080fd5b8135818111156151b3576151b3614a4d565b6151c5601f8201601f19168501614a8c565b915080825236848285010111156151db57600080fd5b808484018584013760009082019093019290925250604082015292915050565b600061ffff808316818516808303821115614faa57614faa614e19565b600181815b8085111561525357816000190482111561523957615239614e19565b8085161561524657918102915b93841c939080029061521d565b509250929050565b60008261526a57506001610a54565b8161527757506000610a54565b816001811461528d5760028114615297576152b3565b6001915050610a54565b60ff8411156152a8576152a8614e19565b50506001821b610a54565b5060208310610133831016604e8410600b84101617156152d6575081810a610a54565b6152e08383615218565b80600019048211156152f4576152f4614e19565b029392505050565b60006125ad60ff84168361525b565b60008161531a5761531a614e19565b506000190190565b8881528760208201528660408201526001600160a01b038616606082015267ffffffffffffffff8516608082015260e060a0820152600061536660e08301866150e6565b82810360c0840152838152838560208301376000602085830101526020601f19601f860116820101915050999850505050505050505056fea264697066735822122067db7a707d6e781088d1ec391c13c78844a6370488f1a5eca731a1efb57d8d0064736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0000000000000000000000000000000000000000000000000000000000076a7000000000000000000000000000000000000000000000000000000000000002328000000000000000000000000035f210e5d14054e8ae5a6cfa76d643aa200d56e00000000000000000000000084f67f75daf6d57aef500e0c85c77b7b3bbc92a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c8000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000020000000000000000000000006b175474e89094c44da98b954eedeac495271d0f000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _underlying (address): 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0
Arg [1] : _minLockPeriod (uint64): 7776000
Arg [2] : _investPct (uint16): 9000
Arg [3] : _treasury (address): 0x035F210e5d14054E8AE5A6CFA76d643aA200D56E
Arg [4] : _admin (address): 0x84f67f75DAf6D57Aef500E0c85C77B7b3bBc92A9
Arg [5] : _perfFeePct (uint16): 0
Arg [6] : _lossTolerancePct (uint16): 200
Arg [7] : _swapPools (tuple[]): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput],System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
17 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f98805a4e8be255a32880fdec7f6728c6568ba0
Arg [1] : 000000000000000000000000000000000000000000000000000000000076a700
Arg [2] : 0000000000000000000000000000000000000000000000000000000000002328
Arg [3] : 000000000000000000000000035f210e5d14054e8ae5a6cfa76d643aa200d56e
Arg [4] : 00000000000000000000000084f67f75daf6d57aef500e0c85c77b7b3bbc92a9
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [6] : 00000000000000000000000000000000000000000000000000000000000000c8
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [9] : 0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f
Arg [10] : 000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [13] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [14] : 000000000000000000000000ed279fdd11ca84beef15af5d39bb4d4bee23f0ca
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.999118 | 14,284.0497 | $14,271.46 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.