Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 2,817 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Withdraw ETH | 20688537 | 59 days ago | IN | 0 ETH | 0.00019907 | ||||
Withdraw ETH | 20688531 | 59 days ago | IN | 0 ETH | 0.00028507 | ||||
Withdraw ETH | 16891915 | 592 days ago | IN | 0 ETH | 0.00765036 | ||||
Withdraw ETH | 16218286 | 686 days ago | IN | 0 ETH | 0.00224704 | ||||
Withdraw ETH | 16031088 | 712 days ago | IN | 0 ETH | 0.00230052 | ||||
Withdraw ETH | 16031083 | 712 days ago | IN | 0 ETH | 0.0021673 | ||||
Withdraw ETH | 16031078 | 712 days ago | IN | 0 ETH | 0.00241465 | ||||
Withdraw ETH | 16031073 | 712 days ago | IN | 0 ETH | 0.0024483 | ||||
Withdraw ETH | 16031055 | 712 days ago | IN | 0 ETH | 0.00235963 | ||||
Withdraw ETH | 16031048 | 712 days ago | IN | 0 ETH | 0.00289008 | ||||
Withdraw ETH | 16031040 | 712 days ago | IN | 0 ETH | 0.00255783 | ||||
Withdraw ETH | 16031022 | 712 days ago | IN | 0 ETH | 0.00235789 | ||||
Withdraw ETH | 15533657 | 782 days ago | IN | 0 ETH | 0.00194372 | ||||
Withdraw ETH | 15532629 | 782 days ago | IN | 0 ETH | 0.00128158 | ||||
Withdraw ETH | 15532335 | 782 days ago | IN | 0 ETH | 0.00165611 | ||||
Withdraw | 15404490 | 803 days ago | IN | 0 ETH | 0.00358668 | ||||
Withdraw | 15404485 | 803 days ago | IN | 0 ETH | 0.00339682 | ||||
Withdraw ETH | 15404480 | 803 days ago | IN | 0 ETH | 0.0036659 | ||||
Withdraw | 15404471 | 803 days ago | IN | 0 ETH | 0.00214222 | ||||
Withdraw ETH | 15404451 | 803 days ago | IN | 0 ETH | 0.00243434 | ||||
Withdraw ETH | 15377091 | 807 days ago | IN | 0 ETH | 0.00107187 | ||||
Withdraw ETH | 15217948 | 832 days ago | IN | 0 ETH | 0.00215955 | ||||
Withdraw ETH | 15213459 | 833 days ago | IN | 0 ETH | 0.00555751 | ||||
Withdraw ETH | 15096352 | 851 days ago | IN | 0 ETH | 0.00733152 | ||||
Withdraw ETH | 14993883 | 869 days ago | IN | 0 ETH | 0.00376118 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20688531 | 59 days ago | 1 ETH | ||||
20688531 | 59 days ago | 1 ETH | ||||
16891915 | 592 days ago | 0.4 ETH | ||||
16891915 | 592 days ago | 0.4 ETH | ||||
16218286 | 686 days ago | 3 ETH | ||||
16218286 | 686 days ago | 3 ETH | ||||
16031088 | 712 days ago | 0.1 ETH | ||||
16031088 | 712 days ago | 0.1 ETH | ||||
16031083 | 712 days ago | 0.05 ETH | ||||
16031083 | 712 days ago | 0.05 ETH | ||||
16031078 | 712 days ago | 0.1 ETH | ||||
16031078 | 712 days ago | 0.1 ETH | ||||
16031073 | 712 days ago | 0.1 ETH | ||||
16031073 | 712 days ago | 0.1 ETH | ||||
16031055 | 712 days ago | 0.05 ETH | ||||
16031055 | 712 days ago | 0.05 ETH | ||||
16031048 | 712 days ago | 0.1 ETH | ||||
16031048 | 712 days ago | 0.1 ETH | ||||
16031040 | 712 days ago | 0.08 ETH | ||||
16031040 | 712 days ago | 0.08 ETH | ||||
16031022 | 712 days ago | 0.15 ETH | ||||
16031022 | 712 days ago | 0.15 ETH | ||||
15533657 | 782 days ago | 0.50754999 ETH | ||||
15533657 | 782 days ago | 0.50754999 ETH | ||||
15532629 | 782 days ago | 2.03699999 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AllPairVault
Compiler Version
v0.8.3+commit.8d00100c
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/proxy/Clones.sol"; import "contracts/OndoRegistryClient.sol"; import "contracts/TrancheToken.sol"; import "contracts/interfaces/IStrategy.sol"; import "contracts/interfaces/ITrancheToken.sol"; import "contracts/interfaces/IStrategy.sol"; import "contracts/interfaces/IPairVault.sol"; import "contracts/interfaces/IFeeCollector.sol"; /** * @title A container for all Vaults * @notice Vaults are created and managed here * @dev Because Ethereum transactions are so expensive, * we reinvent an OO system in this code. There are 4 primary * functions: * * deposit, withdraw: investors can add remove funds into a * particular tranche in a Vault. * invest, redeem: a strategist pushes the Vault to buy/sell LP tokens in * an underlying AMM */ contract AllPairVault is OndoRegistryClient, IPairVault { using OLib for OLib.Investor; using SafeERC20 for IERC20; using Address for address; using EnumerableSet for EnumerableSet.UintSet; // A Vault object is parameterized by these values. struct Vault { mapping(OLib.Tranche => Asset) assets; // Assets corresponding to each tranche IStrategy strategy; // Shared contract that interacts with AMMs address creator; // Account that calls createVault address strategist; // Has the right to call invest() and redeem(), and harvest() if strategy supports it address rollover; // Manager of investment auto-rollover, if any uint256 rolloverId; uint256 hurdleRate; // Return offered to senior tranche OLib.State state; // Current state of Vault uint256 startAt; // Time when the Vault is unpaused to begin accepting deposits uint256 investAt; // Time when investors can't move funds, strategist can invest uint256 redeemAt; // Time when strategist can redeem LP tokens, investors can withdraw uint256 performanceFee; // Optional fee on junior tranche goes to strategist } // (TrancheToken address => (investor address => OLib.Investor) mapping(address => mapping(address => OLib.Investor)) investors; // An instance of TrancheToken from which all other tokens are cloned address public immutable trancheTokenImpl; // Address that collects performance fees IFeeCollector public performanceFeeCollector; // Locate Vault by hashing metadata about the product mapping(uint256 => Vault) private Vaults; // Locate Vault by starting from the TrancheToken address mapping(address => uint256) public VaultsByTokens; // All Vault IDs EnumerableSet.UintSet private vaultIDs; // Access restriction to registered strategist modifier onlyStrategist(uint256 _vaultId) { require(msg.sender == Vaults[_vaultId].strategist, "Invalid caller"); _; } // Access restriction to registered rollover modifier onlyRollover(uint256 _vaultId, uint256 _rolloverId) { Vault storage vault_ = Vaults[_vaultId]; require( msg.sender == vault_.rollover && _rolloverId == vault_.rolloverId, "Invalid caller" ); _; } // Access is only rollover if rollover addr nonzero, else strategist modifier onlyRolloverOrStrategist(uint256 _vaultId) { Vault storage vault_ = Vaults[_vaultId]; address rollover = vault_.rollover; require( (rollover == address(0) && msg.sender == vault_.strategist) || (msg.sender == rollover), "Invalid caller" ); _; } // Guard functions with state machine modifier atState(uint256 _vaultId, OLib.State _state) { require(getState(_vaultId) == _state, "Invalid operation"); _; } // Determine if one can move to a new state. For now the transitions // are strictly linear. No state machines, really. function transition(uint256 _vaultId, OLib.State _nextState) private { Vault storage vault_ = Vaults[_vaultId]; OLib.State curState = vault_.state; if (_nextState == OLib.State.Live) { require(curState == OLib.State.Deposit, "Invalid operation"); require(vault_.investAt <= block.timestamp, "Not time yet"); } else { require( curState == OLib.State.Live && _nextState == OLib.State.Withdraw, "Invalid operation" ); require(vault_.redeemAt <= block.timestamp, "Not time yet"); } vault_.state = _nextState; } // Determine if a Vault can shift to an open state. A Vault is started // in an inactive state. It can only move forward when time has // moved past the starttime. function maybeOpenDeposit(uint256 _vaultId) private { Vault storage vault_ = Vaults[_vaultId]; if (vault_.state == OLib.State.Inactive) { require( vault_.startAt > 0 && vault_.startAt <= block.timestamp, "Not time yet" ); vault_.state = OLib.State.Deposit; } else if (vault_.state != OLib.State.Deposit) { revert("Invalid operation"); } } // modifier onlyETH(uint256 _vaultId, OLib.Tranche _tranche) { // require( // address((getVaultById(_vaultId)).assets[uint256(_tranche)].token) == // address(registry.weth()), // "Not an ETH vault" // ); // _; // } function onlyETH(uint256 _vaultId, OLib.Tranche _tranche) private view { require( address((getVaultById(_vaultId)).assets[uint256(_tranche)].token) == address(registry.weth()), "Not an ETH vault" ); } /** * Event declarations */ event CreatedPair( uint256 indexed vaultId, IERC20 indexed seniorAsset, IERC20 indexed juniorAsset, ITrancheToken seniorToken, ITrancheToken juniorToken ); event SetRollover( address indexed rollover, uint256 indexed rolloverId, uint256 indexed vaultId ); event Deposited( address indexed depositor, uint256 indexed vaultId, uint256 indexed trancheId, uint256 amount ); event Invested( uint256 indexed vaultId, uint256 seniorAmount, uint256 juniorAmount ); event DepositedLP( address indexed depositor, uint256 indexed vaultId, uint256 amount, uint256 senior, uint256 junior ); event RolloverDeposited( address indexed rollover, uint256 indexed rolloverId, uint256 indexed vaultId, uint256 seniorAmount, uint256 juniorAmount ); event Claimed( address indexed depositor, uint256 indexed vaultId, uint256 indexed trancheId, uint256 shares, uint256 excess ); event RolloverClaimed( address indexed rollover, uint256 indexed rolloverId, uint256 indexed vaultId, uint256 seniorAmount, uint256 juniorAmount ); event Redeemed( uint256 indexed vaultId, uint256 seniorReceived, uint256 juniorReceived ); event Withdrew( address indexed depositor, uint256 indexed vaultId, uint256 indexed trancheId, uint256 amount ); event WithdrewLP(address indexed depositor, uint256 amount); event PerformanceFeeSet(uint256 indexed vaultId, uint256 fee); event PerformanceFeeCollectorSet(address indexed collector); /** * @notice Container points back to registry * @dev Hook up this contract to the global registry. */ constructor(address _registry, address _trancheTokenImpl) OndoRegistryClient(_registry) { require(_trancheTokenImpl != address(0), "Invalid target"); trancheTokenImpl = _trancheTokenImpl; } /** * @notice Initialize parameters for a Vault * @dev * @param _params Struct with all initialization info * @return vaultId hashed identifier of Vault used everywhere **/ function createVault(OLib.VaultParams calldata _params) external override whenNotPaused isAuthorized(OLib.CREATOR_ROLE) nonReentrant returns (uint256 vaultId) { require( registry.authorized(OLib.STRATEGY_ROLE, _params.strategy), "Invalid target" ); require( registry.authorized(OLib.STRATEGIST_ROLE, _params.strategist), "Invalid target" ); require(_params.startTime >= block.timestamp, "Invalid start time"); require( _params.enrollment > 0 && _params.duration > 0, "No zero intervals" ); require(_params.hurdleRate < 1e8, "Maximum hurdle is 10000%"); require(denominator <= _params.hurdleRate, "Min hurdle is 100%"); require( _params.seniorAsset != address(0) && _params.seniorAsset != address(this) && _params.juniorAsset != address(0) && _params.juniorAsset != address(this), "Invalid target" ); uint256 investAtTime = _params.startTime + _params.enrollment; uint256 redeemAtTime = investAtTime + _params.duration; TrancheToken seniorITrancheToken; TrancheToken juniorITrancheToken; { vaultId = uint256( keccak256( abi.encode( _params.seniorAsset, _params.juniorAsset, _params.strategy, _params.hurdleRate, _params.startTime, investAtTime, redeemAtTime ) ) ); vaultIDs.add(vaultId); Vault storage vault_ = Vaults[vaultId]; require(address(vault_.strategist) == address(0), "Duplicate"); vault_.strategy = IStrategy(_params.strategy); vault_.creator = msg.sender; vault_.strategist = _params.strategist; vault_.hurdleRate = _params.hurdleRate; vault_.startAt = _params.startTime; vault_.investAt = investAtTime; vault_.redeemAt = redeemAtTime; registry.recycleDeadTokens(2); seniorITrancheToken = TrancheToken( Clones.cloneDeterministic( trancheTokenImpl, keccak256(abi.encodePacked(uint256(0), vaultId)) ) ); juniorITrancheToken = TrancheToken( Clones.cloneDeterministic( trancheTokenImpl, keccak256(abi.encodePacked(uint256(1), vaultId)) ) ); vault_.assets[OLib.Tranche.Senior].token = IERC20(_params.seniorAsset); vault_.assets[OLib.Tranche.Junior].token = IERC20(_params.juniorAsset); vault_.assets[OLib.Tranche.Senior].trancheToken = seniorITrancheToken; vault_.assets[OLib.Tranche.Junior].trancheToken = juniorITrancheToken; vault_.assets[OLib.Tranche.Senior].trancheCap = _params.seniorTrancheCap; vault_.assets[OLib.Tranche.Senior].userCap = _params.seniorUserCap; vault_.assets[OLib.Tranche.Junior].trancheCap = _params.juniorTrancheCap; vault_.assets[OLib.Tranche.Junior].userCap = _params.juniorUserCap; VaultsByTokens[address(seniorITrancheToken)] = vaultId; VaultsByTokens[address(juniorITrancheToken)] = vaultId; if (vault_.startAt == block.timestamp) { vault_.state = OLib.State.Deposit; } IStrategy(_params.strategy).addVault( vaultId, IERC20(_params.seniorAsset), IERC20(_params.juniorAsset) ); seniorITrancheToken.initialize( vaultId, _params.seniorName, _params.seniorSym, address(this) ); juniorITrancheToken.initialize( vaultId, _params.juniorName, _params.juniorSym, address(this) ); } emit CreatedPair( vaultId, IERC20(_params.seniorAsset), IERC20(_params.juniorAsset), seniorITrancheToken, juniorITrancheToken ); } /** * @notice Set the rollover details for a Vault * @dev * @param _vaultId Vault to update * @param _rollover Account of approved rollover agent * @param _rolloverId Rollover fund in RolloverVault */ function setRollover( uint256 _vaultId, address _rollover, uint256 _rolloverId ) external override isAuthorized(OLib.ROLLOVER_ROLE) { Vault storage vault_ = Vaults[_vaultId]; if (vault_.rollover != address(0)) { require( msg.sender == vault_.rollover && _rolloverId == vault_.rolloverId, "Invalid caller" ); } vault_.rollover = _rollover; vault_.rolloverId = _rolloverId; emit SetRollover(_rollover, _rolloverId, _vaultId); } /** @dev Enforce cap on user investment if any */ function depositCapGuard(uint256 _allowedAmount, uint256 _amount) internal pure { require( _allowedAmount == 0 || _amount <= _allowedAmount, "Exceeds user cap" ); } /** * @notice Deposit funds into specific tranche of specific Vault * @dev OLib.Tranche balances are maintained by a unique ERC20 contract * @param _vaultId Specific ID for this Vault * @param _tranche Tranche to be deposited in * @param _amount Amount of tranche asset to transfer to the strategy contract */ function _deposit( uint256 _vaultId, OLib.Tranche _tranche, uint256 _amount, address _payer ) internal whenNotPaused { maybeOpenDeposit(_vaultId); Vault storage vault_ = Vaults[_vaultId]; vault_.assets[_tranche].token.safeTransferFrom( _payer, address(vault_.strategy), _amount ); uint256 _total = vault_.assets[_tranche].deposited += _amount; OLib.Investor storage _investor = investors[address(vault_.assets[_tranche].trancheToken)][msg.sender]; uint256 userSum = _investor.userSums.length > 0 ? _investor.userSums[_investor.userSums.length - 1] + _amount : _amount; depositCapGuard(vault_.assets[_tranche].userCap, userSum); _investor.prefixSums.push(_total); _investor.userSums.push(userSum); emit Deposited(msg.sender, _vaultId, uint256(_tranche), _amount); } function deposit( uint256 _vaultId, OLib.Tranche _tranche, uint256 _amount ) external override nonReentrant { _deposit(_vaultId, _tranche, _amount, msg.sender); } function depositETH(uint256 _vaultId, OLib.Tranche _tranche) external payable override nonReentrant { onlyETH(_vaultId, _tranche); registry.weth().deposit{value: msg.value}(); _deposit(_vaultId, _tranche, msg.value, address(this)); } /** * @notice Called by rollover to deposit funds * @dev Rollover gets priority over other depositors. * @param _vaultId Vault to work on * @param _rolloverId Rollover that is depositing funds * @param _seniorAmount Total available amount of assets * @param _juniorAmount Total available amount of assets */ function depositFromRollover( uint256 _vaultId, uint256 _rolloverId, uint256 _seniorAmount, uint256 _juniorAmount ) external override onlyRollover(_vaultId, _rolloverId) whenNotPaused nonReentrant { maybeOpenDeposit(_vaultId); Vault storage vault_ = Vaults[_vaultId]; Asset storage senior_ = vault_.assets[OLib.Tranche.Senior]; Asset storage junior_ = vault_.assets[OLib.Tranche.Junior]; senior_.deposited += _seniorAmount; junior_.deposited += _juniorAmount; senior_.rolloverDeposited += _seniorAmount; junior_.rolloverDeposited += _juniorAmount; senior_.token.safeTransferFrom( msg.sender, address(vault_.strategy), _seniorAmount ); junior_.token.safeTransferFrom( msg.sender, address(vault_.strategy), _juniorAmount ); emit RolloverDeposited( msg.sender, _rolloverId, _vaultId, _seniorAmount, _juniorAmount ); } /** * @notice Deposit more LP tokens into a Vault that is live * @dev When a Vault is created it establishes a ratio between * senior/junior tranche tokens per LP token. If LP tokens are added * while the Vault is running, it will get the same ratio of tranche * tokens in return, regardless of the current balance in the pool. * @param _vaultId reference to Vault * @param _lpTokens Amount of LP tokens to provide */ function depositLp(uint256 _vaultId, uint256 _lpTokens) external override whenNotPaused nonReentrant atState(_vaultId, OLib.State.Live) returns (uint256 seniorTokensOwed, uint256 juniorTokensOwed) { require(registry.tokenMinting(), "Vault tokens inactive"); Vault storage vault_ = Vaults[_vaultId]; IERC20 pool; (seniorTokensOwed, juniorTokensOwed, pool) = getDepositLp( _vaultId, _lpTokens ); depositCapGuard( vault_.assets[OLib.Tranche.Senior].userCap, seniorTokensOwed ); depositCapGuard( vault_.assets[OLib.Tranche.Junior].userCap, juniorTokensOwed ); vault_.assets[OLib.Tranche.Senior].totalInvested += seniorTokensOwed; vault_.assets[OLib.Tranche.Junior].totalInvested += juniorTokensOwed; vault_.assets[OLib.Tranche.Senior].trancheToken.mint( msg.sender, seniorTokensOwed ); vault_.assets[OLib.Tranche.Junior].trancheToken.mint( msg.sender, juniorTokensOwed ); pool.safeTransferFrom(msg.sender, address(vault_.strategy), _lpTokens); vault_.strategy.addLp(_vaultId, _lpTokens); emit DepositedLP( msg.sender, _vaultId, _lpTokens, seniorTokensOwed, juniorTokensOwed ); } function getDepositLp(uint256 _vaultId, uint256 _lpTokens) public view atState(_vaultId, OLib.State.Live) returns ( uint256 seniorTokensOwed, uint256 juniorTokensOwed, IERC20 pool ) { Vault storage vault_ = Vaults[_vaultId]; (uint256 shares, uint256 vaultShares, IERC20 ammPool) = vault_.strategy.sharesFromLp(_vaultId, _lpTokens); seniorTokensOwed = (vault_.assets[OLib.Tranche.Senior].totalInvested * shares) / vaultShares; juniorTokensOwed = (vault_.assets[OLib.Tranche.Junior].totalInvested * shares) / vaultShares; pool = ammPool; } /** * @notice Invest funds into AMM * @dev Push deposited funds into underlying strategy contract * @param _vaultId Specific id for this Vault * @param _seniorMinIn To ensure you get a decent price * @param _juniorMinIn Same. Passed to addLiquidity on AMM * */ function invest( uint256 _vaultId, uint256 _seniorMinIn, uint256 _juniorMinIn ) external override whenNotPaused nonReentrant onlyRolloverOrStrategist(_vaultId) returns (uint256, uint256) { transition(_vaultId, OLib.State.Live); Vault storage vault_ = Vaults[_vaultId]; investIntoStrategy(vault_, _vaultId, _seniorMinIn, _juniorMinIn); Asset storage senior_ = vault_.assets[OLib.Tranche.Senior]; Asset storage junior_ = vault_.assets[OLib.Tranche.Junior]; senior_.totalInvested = vault_.assets[OLib.Tranche.Senior].originalInvested; junior_.totalInvested = vault_.assets[OLib.Tranche.Junior].originalInvested; emit Invested(_vaultId, senior_.totalInvested, junior_.totalInvested); return (senior_.totalInvested, junior_.totalInvested); } /* * @dev Separate investable amount calculation and strategy call from storage updates to keep the stack down. */ function investIntoStrategy( Vault storage vault_, uint256 _vaultId, uint256 _seniorMinIn, uint256 _juniorMinIn ) private { uint256 seniorInvestableAmount = vault_.assets[OLib.Tranche.Senior].deposited; uint256 seniorCappedAmount = seniorInvestableAmount; if (vault_.assets[OLib.Tranche.Senior].trancheCap > 0) { seniorCappedAmount = min( seniorInvestableAmount, vault_.assets[OLib.Tranche.Senior].trancheCap ); } uint256 juniorInvestableAmount = vault_.assets[OLib.Tranche.Junior].deposited; uint256 juniorCappedAmount = juniorInvestableAmount; if (vault_.assets[OLib.Tranche.Junior].trancheCap > 0) { juniorCappedAmount = min( juniorInvestableAmount, vault_.assets[OLib.Tranche.Junior].trancheCap ); } ( vault_.assets[OLib.Tranche.Senior].originalInvested, vault_.assets[OLib.Tranche.Junior].originalInvested ) = vault_.strategy.invest( _vaultId, seniorCappedAmount, juniorCappedAmount, seniorInvestableAmount - seniorCappedAmount, juniorInvestableAmount - juniorCappedAmount, _seniorMinIn, _juniorMinIn ); } /** * @notice Return undeposited funds and trigger minting in Tranche Token * @dev Because the tranches must be balanced to buy LP tokens at * the right ratio, it is likely that some deposits will not be * accepted. This function transfers that "excess" deposit. Also, it * finally mints the tranche tokens for this customer. * @param _vaultId Reference to specific Vault * @param _tranche which tranche to act on * @return userInvested Total amount actually invested from this tranche * @return excess Any uninvested funds */ function _claim( uint256 _vaultId, OLib.Tranche _tranche, address _receiver ) internal whenNotPaused atState(_vaultId, OLib.State.Live) returns (uint256 userInvested, uint256 excess) { Vault storage vault_ = Vaults[_vaultId]; Asset storage _asset = vault_.assets[_tranche]; ITrancheToken _trancheToken = _asset.trancheToken; OLib.Investor storage investor = investors[address(_trancheToken)][msg.sender]; require(!investor.claimed, "Already claimed"); IStrategy _strategy = vault_.strategy; (userInvested, excess) = investor.getInvestedAndExcess( _getNetOriginalInvested(_asset) ); if (excess > 0) _strategy.withdrawExcess(_vaultId, _tranche, _receiver, excess); if (registry.tokenMinting()) { _trancheToken.mint(msg.sender, userInvested); } investor.claimed = true; emit Claimed(msg.sender, _vaultId, uint256(_tranche), userInvested, excess); return (userInvested, excess); } function claim(uint256 _vaultId, OLib.Tranche _tranche) external override nonReentrant returns (uint256, uint256) { return _claim(_vaultId, _tranche, msg.sender); } function claimETH(uint256 _vaultId, OLib.Tranche _tranche) external override nonReentrant returns (uint256 invested, uint256 excess) { onlyETH(_vaultId, _tranche); (invested, excess) = _claim(_vaultId, _tranche, address(this)); registry.weth().withdraw(excess); safeTransferETH(msg.sender, excess); } /** * @notice Called by rollover to claim both tranches * @dev Triggers minting of tranche tokens. Moves excess to Rollover. * @param _vaultId Vault id * @param _rolloverId Rollover ID * @return srRollInv Amount invested in tranche * @return jrRollInv Amount invested in tranche */ function rolloverClaim(uint256 _vaultId, uint256 _rolloverId) external override whenNotPaused nonReentrant atState(_vaultId, OLib.State.Live) onlyRollover(_vaultId, _rolloverId) returns (uint256 srRollInv, uint256 jrRollInv) { Vault storage vault_ = Vaults[_vaultId]; Asset storage senior_ = vault_.assets[OLib.Tranche.Senior]; Asset storage junior_ = vault_.assets[OLib.Tranche.Junior]; srRollInv = _getRolloverInvested(senior_); jrRollInv = _getRolloverInvested(junior_); if (srRollInv > 0) { senior_.trancheToken.mint(msg.sender, srRollInv); } if (jrRollInv > 0) { junior_.trancheToken.mint(msg.sender, jrRollInv); } if (senior_.rolloverDeposited > srRollInv) { vault_.strategy.withdrawExcess( _vaultId, OLib.Tranche.Senior, msg.sender, senior_.rolloverDeposited - srRollInv ); } if (junior_.rolloverDeposited > jrRollInv) { vault_.strategy.withdrawExcess( _vaultId, OLib.Tranche.Junior, msg.sender, junior_.rolloverDeposited - jrRollInv ); } emit RolloverClaimed( msg.sender, _rolloverId, _vaultId, srRollInv, jrRollInv ); return (srRollInv, jrRollInv); } /** * @notice Redeem funds into AMM * @dev Exchange LP tokens for senior/junior assets. Compute the amount * the senior tranche should get (like 10% more). The senior._received * value should be equal to or less than that expected amount. The * junior.received should be all that's left. * @param _vaultId Specific id for this Vault * @param _seniorMinReceived Compute total expected to redeem, factoring in slippage * @param _juniorMinReceived Same. */ function redeem( uint256 _vaultId, uint256 _seniorMinReceived, uint256 _juniorMinReceived ) external override whenNotPaused nonReentrant onlyRolloverOrStrategist(_vaultId) returns (uint256, uint256) { transition(_vaultId, OLib.State.Withdraw); Vault storage vault_ = Vaults[_vaultId]; Asset storage senior_ = vault_.assets[OLib.Tranche.Senior]; Asset storage junior_ = vault_.assets[OLib.Tranche.Junior]; (senior_.received, junior_.received) = vault_.strategy.redeem( _vaultId, _getSeniorExpected(vault_, senior_), _seniorMinReceived, _juniorMinReceived ); junior_.received -= takePerformanceFee(vault_, _vaultId); emit Redeemed(_vaultId, senior_.received, junior_.received); return (senior_.received, junior_.received); } /** * @notice Investors withdraw funds from Vault * @dev Based on the fraction of ownership in the original pool of invested assets, investors get the same fraction of the resulting pile of assets. All funds are withdrawn. * @param _vaultId Specific ID for this Vault * @param _tranche Tranche to be deposited in * @return tokensToWithdraw Amount investor received from transfer */ function _withdraw( uint256 _vaultId, OLib.Tranche _tranche, address _receiver ) internal whenNotPaused atState(_vaultId, OLib.State.Withdraw) returns (uint256 tokensToWithdraw) { Vault storage vault_ = Vaults[_vaultId]; Asset storage asset_ = vault_.assets[_tranche]; (, , , tokensToWithdraw) = vaultInvestor(_vaultId, _tranche); ITrancheToken token_ = asset_.trancheToken; if (registry.tokenMinting()) { uint256 bal = token_.balanceOf(msg.sender); if (bal > 0) { token_.burn(msg.sender, bal); } } asset_.token.safeTransferFrom( address(vault_.strategy), _receiver, tokensToWithdraw ); investors[address(asset_.trancheToken)][msg.sender].withdrawn = true; emit Withdrew(msg.sender, _vaultId, uint256(_tranche), tokensToWithdraw); return tokensToWithdraw; } function withdraw(uint256 _vaultId, OLib.Tranche _tranche) external override nonReentrant returns (uint256) { return _withdraw(_vaultId, _tranche, msg.sender); } function withdrawETH(uint256 _vaultId, OLib.Tranche _tranche) external override nonReentrant returns (uint256 amount) { onlyETH(_vaultId, _tranche); amount = _withdraw(_vaultId, _tranche, address(this)); registry.weth().withdraw(amount); safeTransferETH(msg.sender, amount); } receive() external payable { assert(msg.sender == address(registry.weth())); } /** * @notice Exchange the correct ratio of senior/junior tokens to get LP tokens * @dev Burn tranche tokens on both sides and send LP tokens to customer * @param _vaultId reference to Vault * @param _shares Share of lp tokens to withdraw */ function withdrawLp(uint256 _vaultId, uint256 _shares) external override whenNotPaused nonReentrant atState(_vaultId, OLib.State.Live) returns (uint256 seniorTokensNeeded, uint256 juniorTokensNeeded) { require(registry.tokenMinting(), "Vault tokens inactive"); Vault storage vault_ = Vaults[_vaultId]; (seniorTokensNeeded, juniorTokensNeeded) = getWithdrawLp(_vaultId, _shares); vault_.assets[OLib.Tranche.Senior].trancheToken.burn( msg.sender, seniorTokensNeeded ); vault_.assets[OLib.Tranche.Junior].trancheToken.burn( msg.sender, juniorTokensNeeded ); vault_.assets[OLib.Tranche.Senior].totalInvested -= seniorTokensNeeded; vault_.assets[OLib.Tranche.Junior].totalInvested -= juniorTokensNeeded; vault_.strategy.removeLp(_vaultId, _shares, msg.sender); emit WithdrewLP(msg.sender, _shares); } function getWithdrawLp(uint256 _vaultId, uint256 _shares) public view atState(_vaultId, OLib.State.Live) returns (uint256 seniorTokensNeeded, uint256 juniorTokensNeeded) { Vault storage vault_ = Vaults[_vaultId]; (, uint256 totalShares) = vault_.strategy.getVaultInfo(_vaultId); seniorTokensNeeded = (vault_.assets[OLib.Tranche.Senior].totalInvested * _shares) / totalShares; juniorTokensNeeded = (vault_.assets[OLib.Tranche.Junior].totalInvested * _shares) / totalShares; } function getState(uint256 _vaultId) public view override returns (OLib.State) { Vault storage vault_ = Vaults[_vaultId]; return vault_.state; } /** * Helper functions */ /** * @notice Compute performance fee for strategist * @dev If junior makes at least as much as the senior, then charge * a performance fee on junior's earning beyond the hurdle. * @param vault Vault to work on * @return fee Amount of tokens deducted from junior tranche */ function takePerformanceFee(Vault storage vault, uint256 vaultId) internal returns (uint256 fee) { fee = 0; if (address(performanceFeeCollector) != address(0)) { Asset storage junior = vault.assets[OLib.Tranche.Junior]; uint256 juniorHurdle = (junior.totalInvested * vault.hurdleRate) / denominator; if (junior.received > juniorHurdle) { fee = (vault.performanceFee * (junior.received - juniorHurdle)) / denominator; IERC20(junior.token).safeTransferFrom( address(vault.strategy), address(performanceFeeCollector), fee ); performanceFeeCollector.processFee(vaultId, IERC20(junior.token), fee); } } } function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, "ETH transfer failed"); } /** * @notice Multiply senior by hurdle raten * @param vault Vault to work on * @param senior Relevant asset * @return Max value senior can earn for this Vault */ function _getSeniorExpected(Vault storage vault, Asset storage senior) internal view returns (uint256) { return (senior.totalInvested * vault.hurdleRate) / denominator; } function _getNetOriginalInvested(Asset storage asset) internal view returns (uint256) { uint256 o = asset.originalInvested; uint256 r = asset.rolloverDeposited; return o > r ? o - r : 0; } function _getRolloverInvested(Asset storage asset) internal view returns (uint256) { uint256 o = asset.originalInvested; uint256 r = asset.rolloverDeposited; return o > r ? r : o; } /** * Setters */ /** * @notice Set optional performance fee for Vault * @dev Only available before deposits are open * @param _vaultId Vault to work on * @param _performanceFee Percent fee, denominator is 10000 */ function setPerformanceFee(uint256 _vaultId, uint256 _performanceFee) external onlyStrategist(_vaultId) atState(_vaultId, OLib.State.Inactive) { require(_performanceFee <= denominator, "Too high"); Vault storage vault_ = Vaults[_vaultId]; vault_.performanceFee = _performanceFee; emit PerformanceFeeSet(_vaultId, _performanceFee); } /** * @notice All performanceFees go this address. Only set by governance role. * @param _collector Address of collector contract */ function setPerformanceFeeCollector(address _collector) external isAuthorized(OLib.GOVERNANCE_ROLE) { performanceFeeCollector = IFeeCollector(_collector); emit PerformanceFeeCollectorSet(_collector); } function canDeposit(uint256 _vaultId) external view override returns (bool) { Vault storage vault_ = Vaults[_vaultId]; if (vault_.state == OLib.State.Inactive) { return vault_.startAt <= block.timestamp && vault_.startAt > 0; } return vault_.state == OLib.State.Deposit; } function getVaults(uint256 _from, uint256 _to) external view returns (VaultView[] memory vaults) { EnumerableSet.UintSet storage vaults_ = vaultIDs; uint256 len = vaults_.length(); if (len == 0) { return new VaultView[](0); } if (len <= _to) { _to = len - 1; } vaults = new VaultView[](1 + _to - _from); for (uint256 i = _from; i <= _to; i++) { vaults[i] = getVaultById(vaults_.at(i)); } return vaults; } function getVaultByToken(address _trancheToken) external view returns (VaultView memory) { return getVaultById(VaultsByTokens[_trancheToken]); } function getVaultById(uint256 _vaultId) public view override returns (VaultView memory vault) { Vault storage svault_ = Vaults[_vaultId]; mapping(OLib.Tranche => Asset) storage sassets_ = svault_.assets; Asset[] memory assets = new Asset[](2); assets[0] = sassets_[OLib.Tranche.Senior]; assets[1] = sassets_[OLib.Tranche.Junior]; vault = VaultView( _vaultId, assets, svault_.strategy, svault_.creator, svault_.strategist, svault_.rollover, svault_.hurdleRate, svault_.state, svault_.startAt, svault_.investAt, svault_.redeemAt ); } function isPaused() external view override returns (bool) { return paused(); } function getRegistry() external view override returns (address) { return address(registry); } function seniorExpected(uint256 _vaultId) external view override returns (uint256) { Vault storage vault_ = Vaults[_vaultId]; Asset storage senior_ = vault_.assets[OLib.Tranche.Senior]; return _getSeniorExpected(vault_, senior_); } function getUserCaps(uint256 _vaultId) external view override returns (uint256 seniorUserCap, uint256 juniorUserCap) { Vault storage vault_ = Vaults[_vaultId]; return ( vault_.assets[OLib.Tranche.Senior].userCap, vault_.assets[OLib.Tranche.Junior].userCap ); } /* * @return position: total user invested = unclaimed invested amount + tranche token balance * @return claimableBalance: unclaimed invested deposit amount that can be converted into tranche tokens by claiming * @return withdrawableExcess: unclaimed uninvested deposit amount that can be recovered by claiming * @return withdrawableBalance: total amount that the user can redeem their position for by withdrawaing, 0 if the product is still live */ function vaultInvestor(uint256 _vaultId, OLib.Tranche _tranche) public view override returns ( uint256 position, uint256 claimableBalance, uint256 withdrawableExcess, uint256 withdrawableBalance ) { Asset storage asset_ = Vaults[_vaultId].assets[_tranche]; OLib.Investor storage investor_ = investors[address(asset_.trancheToken)][msg.sender]; if (!investor_.withdrawn) { (position, withdrawableExcess) = investor_.getInvestedAndExcess( _getNetOriginalInvested(asset_) ); if (!investor_.claimed) { claimableBalance = position; position += asset_.trancheToken.balanceOf(msg.sender); } else { withdrawableExcess = 0; if (registry.tokenMinting()) { position = asset_.trancheToken.balanceOf(msg.sender); } } if (Vaults[_vaultId].state == OLib.State.Withdraw) { claimableBalance = 0; withdrawableBalance = withdrawableExcess + (asset_.received * position) / asset_.totalInvested; } } } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity ^0.8.0; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable { mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The defaut value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All three of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overloaded; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); _approve(sender, _msgSender(), currentAllowance - amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); _approve(_msgSender(), spender, currentAllowance - subtractedValue); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); _balances[sender] = senderBalance - amount; _balances[recipient] += amount; emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); _balances[account] = accountBalance - amount; _totalSupply -= amount; emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } uint256[45] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /* * @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 ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { function hasRole(bytes32 role, address account) external view returns (bool); function getRoleAdmin(bytes32 role) external view returns (bytes32); function grantRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function renounceRole(bytes32 role, address account) external; } /** * @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 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 {_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 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 override returns (bool) { return _roles[role].members[account]; } /** * @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 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. */ function grantRole(bytes32 role, address account) public virtual override { require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to grant"); _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. */ function revokeRole(bytes32 role, address account) public virtual override { require(hasRole(getRoleAdmin(role), _msgSender()), "AccessControl: sender must be an admin to revoke"); _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 granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ 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. * * [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}. * ==== */ 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 { emit RoleAdminChanged(role, getRoleAdmin(role), adminRole); _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create(0, ptr, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) instance := create2(0, ptr, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt, address deployer) internal pure returns (address predicted) { // solhint-disable-next-line no-inline-assembly assembly { let ptr := mload(0x40) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) mstore(add(ptr, 0x14), shl(0x60, implementation)) mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000) mstore(add(ptr, 0x38), shl(0x60, deployer)) mstore(add(ptr, 0x4c), salt) mstore(add(ptr, 0x6c), keccak256(ptr, 0x37)) predicted := keccak256(add(ptr, 0x37), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress(address implementation, bytes32 salt) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT 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 Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { 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 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 make 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 pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 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"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (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"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev Collection of functions related to array types. */ library Arrays { /** * @dev Searches a sorted `array` and returns the first index that contains * a value greater or equal to `element`. If no such index exists (i.e. all * values in the array are strictly less than `element`), the array length is * returned. Time complexity O(log n). * * `array` is expected to be sorted in ascending order, and to contain no * repeated elements. */ function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { if (array.length == 0) { return 0; } uint256 low = 0; uint256 high = array.length; while (low < high) { uint256 mid = Math.average(low, high); // Note that mid will always be strictly less than high (i.e. it will be a valid array index) // because Math.average rounds down (it does integer division with truncation). if (array[mid] > element) { high = mid; } else { low = mid + 1; } } // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. if (low > 0 && array[low - 1] == element) { return low - 1; } else { return low; } } }
// SPDX-License-Identifier: MIT 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) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT 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 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 pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping (bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require(set._values.length > index, "EnumerableSet: index out of bounds"); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "./OndoRegistryClientInitializable.sol"; abstract contract OndoRegistryClient is OndoRegistryClientInitializable { constructor(address _registry) { __OndoRegistryClient__initialize(_registry); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "contracts/interfaces/IRegistry.sol"; import "contracts/libraries/OndoLibrary.sol"; abstract contract OndoRegistryClientInitializable is Initializable, ReentrancyGuard, Pausable { using SafeERC20 for IERC20; IRegistry public registry; uint256 public denominator; function __OndoRegistryClient__initialize(address _registry) internal initializer { require(_registry != address(0), "Invalid registry address"); registry = IRegistry(_registry); denominator = registry.denominator(); } /** * @notice General ACL checker * @param _role Role as defined in OndoLibrary */ modifier isAuthorized(bytes32 _role) { require(registry.authorized(_role, msg.sender), "Unauthorized"); _; } /* * @notice Helper to expose a Pausable interface to tools */ function paused() public view virtual override returns (bool) { return registry.paused() || super.paused(); } function pause() external virtual isAuthorized(OLib.PANIC_ROLE) { super._pause(); } function unpause() external virtual isAuthorized(OLib.GUARDIAN_ROLE) { super._unpause(); } /** * @notice Grab tokens and send to caller * @dev If the _amount[i] is 0, then transfer all the tokens * @param _tokens List of tokens * @param _amounts Amount of each token to send */ function _rescueTokens(address[] calldata _tokens, uint256[] memory _amounts) internal virtual { for (uint256 i = 0; i < _tokens.length; i++) { uint256 amount = _amounts[i]; if (amount == 0) { amount = IERC20(_tokens[i]).balanceOf(address(this)); } IERC20(_tokens[i]).safeTransfer(msg.sender, amount); } } function rescueTokens(address[] calldata _tokens, uint256[] memory _amounts) public whenPaused isAuthorized(OLib.GUARDIAN_ROLE) { require(_tokens.length == _amounts.length, "Invalid array sizes"); _rescueTokens(_tokens, _amounts); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "contracts/interfaces/IPairVault.sol"; import "contracts/interfaces/ITrancheToken.sol"; import "contracts/interfaces/IBasicVault.sol"; /** * @title Fixed duration tokens representing tranches * @notice For every Vault, for every tranche, this ERC20 token enables trading. * @dev Since these are short-lived tokens and we are producing lots * of them, this uses clones to cheaply create many instance. in * practice this is not upgradeable, we use openzeppelin's clone */ contract TrancheToken is ERC20Upgradeable, ITrancheToken, OwnableUpgradeable { IBasicVault public vault; uint256 public vaultId; modifier whenNotPaused { require(!vault.isPaused(), "Global pause in effect"); _; } modifier onlyRegistry { require( vault.getRegistry() == msg.sender, "Invalid access: Only Registry can call" ); _; } function initialize( uint256 _vaultId, string calldata _name, string calldata _symbol, address _vault ) external initializer { __Ownable_init(); __ERC20_init(_name, _symbol); vault = IBasicVault(_vault); vaultId = _vaultId; } function mint(address _account, uint256 _amount) external override whenNotPaused onlyOwner { _mint(_account, _amount); } function burn(address _account, uint256 _amount) external override whenNotPaused onlyOwner { _burn(_account, _amount); } function transfer(address _account, uint256 _amount) public override(ERC20Upgradeable, IERC20Upgradeable) whenNotPaused returns (bool) { return super.transfer(_account, _amount); } function transferFrom( address _from, address _to, uint256 _amount ) public override(ERC20Upgradeable, IERC20Upgradeable) whenNotPaused returns (bool) { return super.transferFrom(_from, _to, _amount); } function approve(address _account, uint256 _amount) public override(ERC20Upgradeable, IERC20Upgradeable) whenNotPaused returns (bool) { return super.approve(_account, _amount); } function destroy(address payable _receiver) external override whenNotPaused onlyRegistry { selfdestruct(_receiver); } function increaseAllowance(address spender, uint256 addedValue) public override(ERC20Upgradeable) whenNotPaused returns (bool) { return super.increaseAllowance(spender, addedValue); } function decreaseAllowance(address spender, uint256 subtractedValue) public override(ERC20Upgradeable) whenNotPaused returns (bool) { return super.decreaseAllowance(spender, subtractedValue); } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; interface IBasicVault { function isPaused() external view returns (bool); function getRegistry() external view returns (address); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IFeeCollector { function processFee( uint256 vaultId, IERC20 token, uint256 feeSent ) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "contracts/libraries/OndoLibrary.sol"; import "contracts/interfaces/ITrancheToken.sol"; import "contracts/interfaces/IStrategy.sol"; import "contracts/interfaces/IBasicVault.sol"; interface IPairVault is IBasicVault { // Container to return Vault info to caller struct VaultView { uint256 id; Asset[] assets; IStrategy strategy; // Shared contract that interacts with AMMs address creator; // Account that calls createVault address strategist; // Has the right to call invest() and redeem(), and harvest() if strategy supports it address rollover; uint256 hurdleRate; // Return offered to senior tranche OLib.State state; // Current state of Vault uint256 startAt; // Time when the Vault is unpaused to begin accepting deposits uint256 investAt; // Time when investors can't move funds, strategist can invest uint256 redeemAt; // Time when strategist can redeem LP tokens, investors can withdraw } // Track the asset type and amount in different stages struct Asset { IERC20 token; ITrancheToken trancheToken; uint256 trancheCap; uint256 userCap; uint256 deposited; uint256 originalInvested; uint256 totalInvested; // not literal 1:1, originalInvested + proportional lp from mid-term uint256 received; uint256 rolloverDeposited; } function getState(uint256 _vaultId) external view returns (OLib.State); function createVault(OLib.VaultParams calldata _params) external returns (uint256 vaultId); function deposit( uint256 _vaultId, OLib.Tranche _tranche, uint256 _amount ) external; function depositETH(uint256 _vaultId, OLib.Tranche _tranche) external payable; function depositLp(uint256 _vaultId, uint256 _amount) external returns (uint256 seniorTokensOwed, uint256 juniorTokensOwed); function invest( uint256 _vaultId, uint256 _seniorMinOut, uint256 _juniorMinOut ) external returns (uint256, uint256); function redeem( uint256 _vaultId, uint256 _seniorMinOut, uint256 _juniorMinOut ) external returns (uint256, uint256); function withdraw(uint256 _vaultId, OLib.Tranche _tranche) external returns (uint256); function withdrawETH(uint256 _vaultId, OLib.Tranche _tranche) external returns (uint256); function withdrawLp(uint256 _vaultId, uint256 _amount) external returns (uint256, uint256); function claim(uint256 _vaultId, OLib.Tranche _tranche) external returns (uint256, uint256); function claimETH(uint256 _vaultId, OLib.Tranche _tranche) external returns (uint256, uint256); function depositFromRollover( uint256 _vaultId, uint256 _rolloverId, uint256 _seniorAmount, uint256 _juniorAmount ) external; function rolloverClaim(uint256 _vaultId, uint256 _rolloverId) external returns (uint256, uint256); function setRollover( uint256 _vaultId, address _rollover, uint256 _rolloverId ) external; function canDeposit(uint256 _vaultId) external view returns (bool); // function canTransition(uint256 _vaultId, OLib.State _state) // external // view // returns (bool); function getVaultById(uint256 _vaultId) external view returns (VaultView memory); function vaultInvestor(uint256 _vaultId, OLib.Tranche _tranche) external view returns ( uint256 position, uint256 claimableBalance, uint256 withdrawableExcess, uint256 withdrawableBalance ); function seniorExpected(uint256 _vaultId) external view returns (uint256); function getUserCaps(uint256 _vaultId) external view returns (uint256 seniorUserCap, uint256 juniorUserCap); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts/access/AccessControl.sol"; import "contracts/interfaces/IWETH.sol"; /** * @title Global values used by many contracts * @notice This is mostly used for access control */ interface IRegistry is IAccessControl { function paused() external view returns (bool); function pause() external; function unpause() external; function tokenMinting() external view returns (bool); function denominator() external view returns (uint256); function weth() external view returns (IWETH); function authorized(bytes32 _role, address _account) external view returns (bool); function enableTokens() external; function disableTokens() external; function recycleDeadTokens(uint256 _tranches) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "contracts/libraries/OndoLibrary.sol"; import "contracts/interfaces/IPairVault.sol"; interface IStrategy { // Additional info stored for each Vault struct Vault { IPairVault origin; // who created this Vault IERC20 pool; // the DEX pool IERC20 senior; // senior asset in pool IERC20 junior; // junior asset in pool uint256 shares; // number of shares for ETF-style mid-duration entry/exit uint256 seniorExcess; // unused senior deposits uint256 juniorExcess; // unused junior deposits } function vaults(uint256 vaultId) external view returns ( IPairVault origin, IERC20 pool, IERC20 senior, IERC20 junior, uint256 shares, uint256 seniorExcess, uint256 juniorExcess ); function addVault( uint256 _vaultId, IERC20 _senior, IERC20 _junior ) external; function addLp(uint256 _vaultId, uint256 _lpTokens) external; function removeLp( uint256 _vaultId, uint256 _shares, address to ) external; function getVaultInfo(uint256 _vaultId) external view returns (IERC20, uint256); function invest( uint256 _vaultId, uint256 _totalSenior, uint256 _totalJunior, uint256 _extraSenior, uint256 _extraJunior, uint256 _seniorMinOut, uint256 _juniorMinOut ) external returns (uint256 seniorInvested, uint256 juniorInvested); function sharesFromLp(uint256 vaultId, uint256 lpTokens) external view returns ( uint256 shares, uint256 vaultShares, IERC20 pool ); function lpFromShares(uint256 vaultId, uint256 shares) external view returns (uint256 lpTokens, uint256 vaultShares); function redeem( uint256 _vaultId, uint256 _seniorExpected, uint256 _seniorMinOut, uint256 _juniorMinOut ) external returns (uint256, uint256); function withdrawExcess( uint256 _vaultId, OLib.Tranche tranche, address to, uint256 amount ) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol"; interface ITrancheToken is IERC20Upgradeable { function mint(address _account, uint256 _amount) external; function burn(address _account, uint256 _amount) external; function destroy(address payable _receiver) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint256 wad) external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.3; import "@openzeppelin/contracts/utils/Arrays.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; //import "@openzeppelin/contracts/utils/Address.sol"; /** * @title Helper functions */ library OLib { using Arrays for uint256[]; using OLib for OLib.Investor; // State transition per Vault. Just linear transitions. enum State {Inactive, Deposit, Live, Withdraw} // Only supports 2 tranches for now enum Tranche {Senior, Junior} struct VaultParams { address seniorAsset; address juniorAsset; address strategist; address strategy; uint256 hurdleRate; uint256 startTime; uint256 enrollment; uint256 duration; string seniorName; string seniorSym; string juniorName; string juniorSym; uint256 seniorTrancheCap; uint256 seniorUserCap; uint256 juniorTrancheCap; uint256 juniorUserCap; } struct RolloverParams { VaultParams vault; address strategist; string seniorName; string seniorSym; string juniorName; string juniorSym; } bytes32 public constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE"); bytes32 public constant PANIC_ROLE = keccak256("PANIC_ROLE"); bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); bytes32 public constant DEPLOYER_ROLE = keccak256("DEPLOYER_ROLE"); bytes32 public constant CREATOR_ROLE = keccak256("CREATOR_ROLE"); bytes32 public constant STRATEGIST_ROLE = keccak256("STRATEGIST_ROLE"); bytes32 public constant VAULT_ROLE = keccak256("VAULT_ROLE"); bytes32 public constant ROLLOVER_ROLE = keccak256("ROLLOVER_ROLE"); bytes32 public constant STRATEGY_ROLE = keccak256("STRATEGY_ROLE"); // Both sums are running sums. If a user deposits [$1, $5, $3], then // userSums would be [$1, $6, $9]. You can figure out the deposit // amount be subtracting userSums[i]-userSum[i-1]. // prefixSums is the total deposited for all investors + this // investors deposit at the time this deposit is made. So at // prefixSum[0], it would be $1 + totalDeposits, where totalDeposits // could be $1000 because other investors have put in money. struct Investor { uint256[] userSums; uint256[] prefixSums; bool claimed; bool withdrawn; } /** * @dev Given the total amount invested by the Vault, we want to find * out how many of this investor's deposits were actually * used. Use findUpperBound on the prefixSum to find the point * where total deposits were accepted. For example, if $2000 was * deposited by all investors and $1000 was invested, then some * position in the prefixSum splits the array into deposits that * got in, and deposits that didn't get in. That same position * maps to userSums. This is the user's deposits that got * in. Since we are keeping track of the sums, we know at that * position the total deposits for a user was $15, even if it was * 15 $1 deposits. And we know the amount that didn't get in is * the last value in userSum - the amount that got it. * @param investor A specific investor * @param invested The total amount invested by this Vault */ function getInvestedAndExcess(Investor storage investor, uint256 invested) internal view returns (uint256 userInvested, uint256 excess) { uint256[] storage prefixSums_ = investor.prefixSums; uint256 length = prefixSums_.length; if (length == 0) { // There were no deposits. Return 0, 0. return (userInvested, excess); } uint256 leastUpperBound = prefixSums_.findUpperBound(invested); if (length == leastUpperBound) { // All deposits got in, no excess. Return total deposits, 0 userInvested = investor.userSums[length - 1]; return (userInvested, excess); } uint256 prefixSum = prefixSums_[leastUpperBound]; if (prefixSum == invested) { // Not all deposits got in, but there are no partial deposits userInvested = investor.userSums[leastUpperBound]; excess = investor.userSums[length - 1] - userInvested; } else { // Let's say some of my deposits got in. The last deposit, // however, was $100 and only $30 got in. Need to split that // deposit so $30 got in, $70 is excess. userInvested = leastUpperBound > 0 ? investor.userSums[leastUpperBound - 1] : 0; uint256 depositAmount = investor.userSums[leastUpperBound] - userInvested; if (prefixSum - depositAmount < invested) { userInvested += (depositAmount + invested - prefixSum); excess = investor.userSums[length - 1] - userInvested; } else { excess = investor.userSums[length - 1] - userInvested; } } } } /** * @title Subset of SafeERC20 from openZeppelin * * @dev Some non-standard ERC20 contracts (e.g. Tether) break * `approve` by forcing it to behave like `safeApprove`. This means * `safeIncreaseAllowance` will fail when it tries to adjust the * allowance. The code below simply adds an extra call to * `approve(spender, 0)`. */ library OndoSaferERC20 { using SafeERC20 for IERC20; function ondoSafeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; token.safeApprove(spender, 0); token.safeApprove(spender, newAllowance); } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 100 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_registry","type":"address"},{"internalType":"address","name":"_trancheTokenImpl","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"trancheId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"excess","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"contract IERC20","name":"seniorAsset","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"juniorAsset","type":"address"},{"indexed":false,"internalType":"contract ITrancheToken","name":"seniorToken","type":"address"},{"indexed":false,"internalType":"contract ITrancheToken","name":"juniorToken","type":"address"}],"name":"CreatedPair","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"trancheId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"senior","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"junior","type":"uint256"}],"name":"DepositedLP","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"seniorAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"juniorAmount","type":"uint256"}],"name":"Invested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collector","type":"address"}],"name":"PerformanceFeeCollectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"PerformanceFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"seniorReceived","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"juniorReceived","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rollover","type":"address"},{"indexed":true,"internalType":"uint256","name":"rolloverId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"seniorAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"juniorAmount","type":"uint256"}],"name":"RolloverClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rollover","type":"address"},{"indexed":true,"internalType":"uint256","name":"rolloverId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"seniorAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"juniorAmount","type":"uint256"}],"name":"RolloverDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rollover","type":"address"},{"indexed":true,"internalType":"uint256","name":"rolloverId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"SetRollover","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"trancheId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrew","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrewLP","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"VaultsByTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"canDeposit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"}],"name":"claim","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"}],"name":"claimETH","outputs":[{"internalType":"uint256","name":"invested","type":"uint256"},{"internalType":"uint256","name":"excess","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"seniorAsset","type":"address"},{"internalType":"address","name":"juniorAsset","type":"address"},{"internalType":"address","name":"strategist","type":"address"},{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint256","name":"hurdleRate","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"enrollment","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"string","name":"seniorName","type":"string"},{"internalType":"string","name":"seniorSym","type":"string"},{"internalType":"string","name":"juniorName","type":"string"},{"internalType":"string","name":"juniorSym","type":"string"},{"internalType":"uint256","name":"seniorTrancheCap","type":"uint256"},{"internalType":"uint256","name":"seniorUserCap","type":"uint256"},{"internalType":"uint256","name":"juniorTrancheCap","type":"uint256"},{"internalType":"uint256","name":"juniorUserCap","type":"uint256"}],"internalType":"struct OLib.VaultParams","name":"_params","type":"tuple"}],"name":"createVault","outputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"denominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_rolloverId","type":"uint256"},{"internalType":"uint256","name":"_seniorAmount","type":"uint256"},{"internalType":"uint256","name":"_juniorAmount","type":"uint256"}],"name":"depositFromRollover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_lpTokens","type":"uint256"}],"name":"depositLp","outputs":[{"internalType":"uint256","name":"seniorTokensOwed","type":"uint256"},{"internalType":"uint256","name":"juniorTokensOwed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_lpTokens","type":"uint256"}],"name":"getDepositLp","outputs":[{"internalType":"uint256","name":"seniorTokensOwed","type":"uint256"},{"internalType":"uint256","name":"juniorTokensOwed","type":"uint256"},{"internalType":"contract IERC20","name":"pool","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"getState","outputs":[{"internalType":"enum OLib.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"getUserCaps","outputs":[{"internalType":"uint256","name":"seniorUserCap","type":"uint256"},{"internalType":"uint256","name":"juniorUserCap","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"getVaultById","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract ITrancheToken","name":"trancheToken","type":"address"},{"internalType":"uint256","name":"trancheCap","type":"uint256"},{"internalType":"uint256","name":"userCap","type":"uint256"},{"internalType":"uint256","name":"deposited","type":"uint256"},{"internalType":"uint256","name":"originalInvested","type":"uint256"},{"internalType":"uint256","name":"totalInvested","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"rolloverDeposited","type":"uint256"}],"internalType":"struct IPairVault.Asset[]","name":"assets","type":"tuple[]"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"strategist","type":"address"},{"internalType":"address","name":"rollover","type":"address"},{"internalType":"uint256","name":"hurdleRate","type":"uint256"},{"internalType":"enum OLib.State","name":"state","type":"uint8"},{"internalType":"uint256","name":"startAt","type":"uint256"},{"internalType":"uint256","name":"investAt","type":"uint256"},{"internalType":"uint256","name":"redeemAt","type":"uint256"}],"internalType":"struct IPairVault.VaultView","name":"vault","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_trancheToken","type":"address"}],"name":"getVaultByToken","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract ITrancheToken","name":"trancheToken","type":"address"},{"internalType":"uint256","name":"trancheCap","type":"uint256"},{"internalType":"uint256","name":"userCap","type":"uint256"},{"internalType":"uint256","name":"deposited","type":"uint256"},{"internalType":"uint256","name":"originalInvested","type":"uint256"},{"internalType":"uint256","name":"totalInvested","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"rolloverDeposited","type":"uint256"}],"internalType":"struct IPairVault.Asset[]","name":"assets","type":"tuple[]"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"strategist","type":"address"},{"internalType":"address","name":"rollover","type":"address"},{"internalType":"uint256","name":"hurdleRate","type":"uint256"},{"internalType":"enum OLib.State","name":"state","type":"uint8"},{"internalType":"uint256","name":"startAt","type":"uint256"},{"internalType":"uint256","name":"investAt","type":"uint256"},{"internalType":"uint256","name":"redeemAt","type":"uint256"}],"internalType":"struct IPairVault.VaultView","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_from","type":"uint256"},{"internalType":"uint256","name":"_to","type":"uint256"}],"name":"getVaults","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"contract ITrancheToken","name":"trancheToken","type":"address"},{"internalType":"uint256","name":"trancheCap","type":"uint256"},{"internalType":"uint256","name":"userCap","type":"uint256"},{"internalType":"uint256","name":"deposited","type":"uint256"},{"internalType":"uint256","name":"originalInvested","type":"uint256"},{"internalType":"uint256","name":"totalInvested","type":"uint256"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"rolloverDeposited","type":"uint256"}],"internalType":"struct IPairVault.Asset[]","name":"assets","type":"tuple[]"},{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"address","name":"strategist","type":"address"},{"internalType":"address","name":"rollover","type":"address"},{"internalType":"uint256","name":"hurdleRate","type":"uint256"},{"internalType":"enum OLib.State","name":"state","type":"uint8"},{"internalType":"uint256","name":"startAt","type":"uint256"},{"internalType":"uint256","name":"investAt","type":"uint256"},{"internalType":"uint256","name":"redeemAt","type":"uint256"}],"internalType":"struct IPairVault.VaultView[]","name":"vaults","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"getWithdrawLp","outputs":[{"internalType":"uint256","name":"seniorTokensNeeded","type":"uint256"},{"internalType":"uint256","name":"juniorTokensNeeded","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_seniorMinIn","type":"uint256"},{"internalType":"uint256","name":"_juniorMinIn","type":"uint256"}],"name":"invest","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFeeCollector","outputs":[{"internalType":"contract IFeeCollector","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_seniorMinReceived","type":"uint256"},{"internalType":"uint256","name":"_juniorMinReceived","type":"uint256"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_rolloverId","type":"uint256"}],"name":"rolloverClaim","outputs":[{"internalType":"uint256","name":"srRollInv","type":"uint256"},{"internalType":"uint256","name":"jrRollInv","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"}],"name":"seniorExpected","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_performanceFee","type":"uint256"}],"name":"setPerformanceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collector","type":"address"}],"name":"setPerformanceFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"address","name":"_rollover","type":"address"},{"internalType":"uint256","name":"_rolloverId","type":"uint256"}],"name":"setRollover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trancheTokenImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"}],"name":"vaultInvestor","outputs":[{"internalType":"uint256","name":"position","type":"uint256"},{"internalType":"uint256","name":"claimableBalance","type":"uint256"},{"internalType":"uint256","name":"withdrawableExcess","type":"uint256"},{"internalType":"uint256","name":"withdrawableBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"enum OLib.Tranche","name":"_tranche","type":"uint8"}],"name":"withdrawETH","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultId","type":"uint256"},{"internalType":"uint256","name":"_shares","type":"uint256"}],"name":"withdrawLp","outputs":[{"internalType":"uint256","name":"seniorTokensNeeded","type":"uint256"},{"internalType":"uint256","name":"juniorTokensNeeded","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200612a3803806200612a833981016040819052620000349162000295565b600180556002805460ff19169055816200004e81620000b3565b506001600160a01b0381166200009c5760405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a59081d185c99d95d60921b60448201526064015b60405180910390fd5b60601b6001600160601b03191660805250620002e5565b600054610100900460ff1680620000cd575060005460ff16155b620001325760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840162000093565b600054610100900460ff1615801562000155576000805461ffff19166101011790555b6001600160a01b038216620001ad5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420726567697374727920616464726573730000000000000000604482015260640162000093565b81600260016101000a8154816001600160a01b0302191690836001600160a01b03160217905550600260019054906101000a90046001600160a01b03166001600160a01b03166396ce07956040518163ffffffff1660e01b815260040160206040518083038186803b1580156200022357600080fd5b505afa15801562000238573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200025e9190620002cc565b600355801562000274576000805461ff00191690555b5050565b80516001600160a01b03811681146200029057600080fd5b919050565b60008060408385031215620002a8578182fd5b620002b38362000278565b9150620002c36020840162000278565b90509250929050565b600060208284031215620002de578081fd5b5051919050565b60805160601c615e1862000312600039600081816103b80152818161156201526115a90152615e186000f3fe6080604052600436106101ee5760003560e01c806379aba36d1161011357806396ce0795116100ab578063b98cca371161006f578063b98cca371461076e578063c7c311371461079b578063cdce1bef146107bb578063d066a4fa146107ce578063fdbb3aea146107ee576102a9565b806396ce0795146106e3578063b187bd26146106f9578063b1e3a9411461070e578063b4260cbc1461072e578063b81922051461074e576102a9565b806379aba36d146105ad5780637b103999146105cd5780637c61494d146105f25780637debdea6146106215780638456cb59146106415780638be74d96146106565780638f6175d114610676578063903d42961461069657806394708776146106b6576102a9565b80634011b97a116101865780634011b97a1461043c57806344c9af281461046957806351df78b4146104a95780635ab1bd53146104c95780635c975abb146104ed5780635ea171981461050257806360798cab1461054d578063674a8c551461056d578063795191ed1461058d576102a9565b806317d965e4146102ae57806327ac373a146102ce5780632faf3ea6146103135780633619b4641461034857806339443b8e146103765780633b1c91c7146103a65780633bf8d620146103e75780633f3d8fe7146104075780633f4ba83a14610427576102a9565b366102a957600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b15801561024157600080fd5b505afa158015610255573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102799190615588565b6001600160a01b0316336001600160a01b0316146102a757634e487b7160e01b600052600160045260246000fd5b005b600080fd5b3480156102ba57600080fd5b506102a76102c936600461560d565b61080e565b3480156102da57600080fd5b506102ee6102e9366004615644565b610991565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561031f57600080fd5b5061033361032e366004615644565b610c74565b6040805192835260208301919091520161030a565b34801561035457600080fd5b506103686103633660046155dd565b610cbc565b60405190815260200161030a565b34801561038257600080fd5b506103966103913660046155dd565b610cea565b604051901515815260200161030a565b3480156103b257600080fd5b506103da7f000000000000000000000000000000000000000000000000000000000000000081565b60405161030a9190615952565b3480156103f357600080fd5b506102a7610402366004615423565b610d77565b34801561041357600080fd5b506103686104223660046155a4565b610eb5565b34801561043357600080fd5b506102a7611959565b34801561044857600080fd5b50610368610457366004615407565b60076020526000908152604090205481565b34801561047557600080fd5b5061049c6104843660046155dd565b60009081526006602052604090206007015460ff1690565b60405161030a91906159f7565b3480156104b557600080fd5b506103686104c4366004615644565b611a27565b3480156104d557600080fd5b506103da60025461010090046001600160a01b031690565b3480156104f957600080fd5b50610396611b61565b34801561050e57600080fd5b5061033361051d3660046155dd565b60009081526006602090815260408083208380529091528082206003908101546001845291909220909101549091565b34801561055957600080fd5b506102a761056836600461566f565b611bfb565b34801561057957600080fd5b50610333610588366004615644565b611c38565b34801561059957600080fd5b506103336105a83660046156a3565b611d6f565b3480156105b957600080fd5b506103336105c836600461571f565b6120c0565b3480156105d957600080fd5b506002546103da9061010090046001600160a01b031681565b3480156105fe57600080fd5b5061061261060d3660046156a3565b612222565b60405161030a93929190615c54565b34801561062d57600080fd5b506102a761063c36600461574a565b61238a565b34801561064d57600080fd5b506102a761254d565b34801561066257600080fd5b506005546103da906001600160a01b031681565b34801561068257600080fd5b506103336106913660046156a3565b612618565b3480156106a257600080fd5b506103686106b1366004615644565b61276c565b3480156106c257600080fd5b506106d66106d13660046155dd565b6127ac565b60405161030a9190615bbd565b3480156106ef57600080fd5b5061036860035481565b34801561070557600080fd5b50610396612a5d565b34801561071a57600080fd5b506106d6610729366004615407565b612a67565b34801561073a57600080fd5b506102a76107493660046156a3565b612a97565b34801561075a57600080fd5b5061033361076936600461571f565b612bbe565b34801561077a57600080fd5b5061078e6107893660046156a3565b612dde565b60405161030a919061597f565b3480156107a757600080fd5b506103336107b63660046156a3565b612f19565b6102a76107c9366004615644565b6132d6565b3480156107da57600080fd5b506103336107e93660046156a3565b6133f5565b3480156107fa57600080fd5b506102a7610809366004615407565b61377b565b600254604051631fe1defb60e11b81527ff0983e2b51e2b2ff224c42b1eabc9a0c5025d7bfb63557cd50ce5287048e68089161010090046001600160a01b031690633fc3bdf69061086590849033906004016159e0565b60206040518083038186803b15801561087d57600080fd5b505afa158015610891573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b5919061553b565b6108da5760405162461bcd60e51b81526004016108d190615a8e565b60405180910390fd5b600084815260066020526040902060048101546001600160a01b0316156109365760048101546001600160a01b03163314801561091a5750806005015483145b6109365760405162461bcd60e51b81526004016108d190615ab4565b6004810180546001600160a01b0319166001600160a01b03861690811790915560058201849055604051869185917fd7d4fa7e0ef0027fb55099898c747a0fe2ad536a3d2450103bc133e1f646b75890600090a45050505050565b60008281526006602052604081208190819081908190818760018111156109c857634e487b7160e01b600052602160045260246000fd5b60018111156109e757634e487b7160e01b600052602160045260246000fd5b81526020808201929092526040908101600090812060018101546001600160a01b031682526004845282822033835290935220600281015491925090610100900460ff16610c6957610a42610a3b83613889565b82906138af565b6002830154919750945060ff16610ae95760018201546040516370a0823160e01b81528796506001600160a01b03909116906370a0823190610a88903390600401615952565b60206040518083038186803b158015610aa057600080fd5b505afa158015610ab4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad891906155f5565b610ae29087615cb8565b9550610bfd565b60009350600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3b57600080fd5b505afa158015610b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b73919061553b565b15610bfd5760018201546040516370a0823160e01b81526001600160a01b03909116906370a0823190610baa903390600401615952565b60206040518083038186803b158015610bc257600080fd5b505afa158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa91906155f5565b95505b600360008981526006602052604090206007015460ff166003811115610c3357634e487b7160e01b600052602160045260246000fd5b1415610c6957600094508160060154868360070154610c529190615ce4565b610c5c9190615cd0565b610c669085615cb8565b92505b505092959194509250565b60008060026001541415610c9a5760405162461bcd60e51b81526004016108d190615b86565b6002600155610caa848433613b18565b915091505b6001805590939092509050565b6000818152600660209081526040808320838052918290528220610ce08282613e67565b925050505b919050565b600081815260066020526040812081600782015460ff166003811115610d2057634e487b7160e01b600052602160045260246000fd5b1415610d465742816008015411158015610d3e575060008160080154115b915050610ce5565b6001600782015460ff166003811115610d6f57634e487b7160e01b600052602160045260246000fd5b149392505050565b610d7f611b61565b610d9b5760405162461bcd60e51b81526004016108d190615a38565b600254604051631fe1defb60e11b81527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50419161010090046001600160a01b031690633fc3bdf690610df290849033906004016159e0565b60206040518083038186803b158015610e0a57600080fd5b505afa158015610e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e42919061553b565b610e5e5760405162461bcd60e51b81526004016108d190615a8e565b81518314610ea45760405162461bcd60e51b8152602060048201526013602482015272496e76616c69642061727261792073697a657360681b60448201526064016108d1565b610eaf848484613e91565b50505050565b6000610ebf611b61565b15610edc5760405162461bcd60e51b81526004016108d190615b02565b600254604051631fe1defb60e11b81527f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f9161010090046001600160a01b031690633fc3bdf690610f3390849033906004016159e0565b60206040518083038186803b158015610f4b57600080fd5b505afa158015610f5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f83919061553b565b610f9f5760405162461bcd60e51b81526004016108d190615a8e565b60026001541415610fc25760405162461bcd60e51b81526004016108d190615b86565b600260018190555461010090046001600160a01b0316633fc3bdf67f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c61100e6080870160608801615407565b6040518363ffffffff1660e01b815260040161102b9291906159e0565b60206040518083038186803b15801561104357600080fd5b505afa158015611057573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107b919061553b565b6110975760405162461bcd60e51b81526004016108d190615a66565b60025461010090046001600160a01b0316633fc3bdf67f17a8e30262c1f919c33056d877a3c22b95c2f5e4dac44683c1c2323cd79fbdb06110de6060870160408801615407565b6040518363ffffffff1660e01b81526004016110fb9291906159e0565b60206040518083038186803b15801561111357600080fd5b505afa158015611127573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114b919061553b565b6111675760405162461bcd60e51b81526004016108d190615a66565b428360a0013510156111b05760405162461bcd60e51b8152602060048201526012602482015271496e76616c69642073746172742074696d6560701b60448201526064016108d1565b60008360c001351180156111c8575060008360e00135115b6112085760405162461bcd60e51b81526020600482015260116024820152704e6f207a65726f20696e74657276616c7360781b60448201526064016108d1565b6305f5e10083608001351061125a5760405162461bcd60e51b81526020600482015260186024820152774d6178696d756d20687572646c652069732031303030302560401b60448201526064016108d1565b826080013560035411156112a55760405162461bcd60e51b81526020600482015260126024820152714d696e20687572646c65206973203130302560701b60448201526064016108d1565b60006112b46020850185615407565b6001600160a01b0316141580156112e05750306112d46020850185615407565b6001600160a01b031614155b8015611305575060006112f96040850160208601615407565b6001600160a01b031614155b801561132957503061131d6040850160208601615407565b6001600160a01b031614155b6113455760405162461bcd60e51b81526004016108d190615a66565b600061135960c085013560a0860135615cb8565b9050600061136b60e086013583615cb8565b905060008061137d6020880188615407565b61138d6040890160208a01615407565b61139d60808a0160608b01615407565b604080516001600160a01b0394851660208201529284169083015290911660608201526080888101359082015260a0808901359082015260c0810185905260e081018490526101000160408051601f198184030181529190528051602090910120955061140b600887613fe1565b50600086815260066020526040902060038101546001600160a01b0316156114615760405162461bcd60e51b81526020600482015260096024820152684475706c696361746560b81b60448201526064016108d1565b6114716080890160608a01615407565b6001820180546001600160a01b03929092166001600160a01b0319928316179055600282018054909116331790556114af6060890160408a01615407565b6003820180546001600160a01b0319166001600160a01b039283161790556080890135600683015560a0890135600883015560098201869055600a8201859055600280546040516368e781c560e11b8152600481019290925261010090049091169063d1cf038a90602401600060405180830381600087803b15801561153457600080fd5b505af1158015611548573d6000803e3d6000fd5b505060408051600060208201529081018a90526115a292507f000000000000000000000000000000000000000000000000000000000000000091506060015b60405160208183030381529060405280519060200120613fed565b92506115e57f0000000000000000000000000000000000000000000000000000000000000000600189604051602001611587929190918252602082015260400190565b91506115f46020890189615407565b6000808052602083815260409182902080546001600160a01b0319166001600160a01b03949094169390931790925561163291908a01908a01615407565b600160008181526020849052604080822080546001600160a01b03199081166001600160a01b0396871617909155828052908220830180549091169387169390931790925583918391815260208082019290925260409081016000908120600190810180546001600160a01b0319166001600160a01b039687161790558180528584528282206101808e01356002808301919091556101a08f01356003928301559183528383206101c08f0135928101929092556101e08e0135910155868416815260079092528082208a905591841681522087905560088101544214156117245760078101805460ff191660011790555b6117346080890160608a01615407565b6001600160a01b031663cc8fc76d8861175060208c018c615407565b61176060408d0160208e01615407565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b039182166024840152166044820152606401600060405180830381600087803b1580156117af57600080fd5b505af11580156117c3573d6000803e3d6000fd5b5050506001600160a01b0384169050636ebd362c886117e66101008c018c615c73565b6117f46101208e018e615c73565b306040518763ffffffff1660e01b815260040161181696959493929190615c0b565b600060405180830381600087803b15801561183057600080fd5b505af1158015611844573d6000803e3d6000fd5b5050506001600160a01b0383169050636ebd362c886118676101408c018c615c73565b6118756101608e018e615c73565b306040518763ffffffff1660e01b815260040161189796959493929190615c0b565b600060405180830381600087803b1580156118b157600080fd5b505af11580156118c5573d6000803e3d6000fd5b506118dc93505060408a0191505060208901615407565b6001600160a01b03166118f26020890189615407565b6001600160a01b0316877feea458d0f0292103cf6181411e8b3f4af6309892ec85eac3a3bf166cbce4d03d85856040516119429291906001600160a01b0392831681529116602082015260400190565b60405180910390a450506001805550919392505050565b600254604051631fe1defb60e11b81527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50419161010090046001600160a01b031690633fc3bdf6906119b090849033906004016159e0565b60206040518083038186803b1580156119c857600080fd5b505afa1580156119dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a00919061553b565b611a1c5760405162461bcd60e51b81526004016108d190615a8e565b611a24614087565b50565b600060026001541415611a4c5760405162461bcd60e51b81526004016108d190615b86565b6002600155611a5b83836140ef565b611a66838330614222565b9050600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b158015611ab657600080fd5b505afa158015611aca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aee9190615588565b6001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b8152600401611b1b91815260200190565b600060405180830381600087803b158015611b3557600080fd5b505af1158015611b49573d6000803e3d6000fd5b50505050611b573382614549565b6001805592915050565b6000600260019054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bb157600080fd5b505afa158015611bc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be9919061553b565b80611bf6575060025460ff165b905090565b60026001541415611c1e5760405162461bcd60e51b81526004016108d190615b86565b6002600155611c2f83838333614601565b50506001805550565b60008060026001541415611c5e5760405162461bcd60e51b81526004016108d190615b86565b6002600155611c6d84846140ef565b611c78848430613b18565b8092508193505050600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b158015611cce57600080fd5b505afa158015611ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d069190615588565b6001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b8152600401611d3391815260200190565b600060405180830381600087803b158015611d4d57600080fd5b505af1158015611d61573d6000803e3d6000fd5b50505050610caf3382614549565b600080611d7a611b61565b15611d975760405162461bcd60e51b81526004016108d190615b02565b60026001541415611dba5760405162461bcd60e51b81526004016108d190615b86565b60026001819055849080611de08360009081526006602052604090206007015460ff1690565b6003811115611dff57634e487b7160e01b600052602160045260246000fd5b14611e1c5760405162461bcd60e51b81526004016108d190615b2c565b600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6a57600080fd5b505afa158015611e7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea2919061553b565b611ebe5760405162461bcd60e51b81526004016108d190615b57565b6000868152600660205260409020611ed68787612618565b60008080526020849052604090819020600101549051632770a7eb60e21b81529297509095506001600160a01b031690639dc29fac90611f1c9033908990600401615966565b600060405180830381600087803b158015611f3657600080fd5b505af1158015611f4a573d6000803e3d6000fd5b5050600160008181526020859052604090819020909101549051632770a7eb60e21b81526001600160a01b039091169250639dc29fac9150611f929033908890600401615966565b600060405180830381600087803b158015611fac57600080fd5b505af1158015611fc0573d6000803e3d6000fd5b505060008080526020849052604081206006018054899450909250611fe6908490615d03565b909155505060016000908152602082905260408120600601805486929061200e908490615d03565b90915550506001810154604051637440ae0160e11b81526001600160a01b039091169063e8815c0290612049908a908a903390600401615c54565b600060405180830381600087803b15801561206357600080fd5b505af1158015612077573d6000803e3d6000fd5b50506040518881523392507fde0520231a263824b6834133aeea4afdd1408d02d31aabe77e8f3b625467c6ba915060200160405180910390a25050600180555090939092509050565b6000806120cb611b61565b156120e85760405162461bcd60e51b81526004016108d190615b02565b6002600154141561210b5760405162461bcd60e51b81526004016108d190615b86565b6002600155600085815260066020526040902060048101548691906001600160a01b031680158015612149575060038201546001600160a01b031633145b8061215c5750336001600160a01b038216145b6121785760405162461bcd60e51b81526004016108d190615ab4565b6121838860026148e5565b600088815260066020526040902061219d818a8a8a614a53565b600080805260208281526040808320600184529281902060058085015460068087019182559183015491830182905554835190815293840152815190928d927f15294ad9d42e2bbd446d4ff6ca28fef807d1631ad53c688303fe468410830f3292918290030190a260069182015491015460018055909a909950975050505050505050565b60008080846002806122468360009081526006602052604090206007015460ff1690565b600381111561226557634e487b7160e01b600052602160045260246000fd5b146122825760405162461bcd60e51b81526004016108d190615b2c565b600087815260066020526040808220600181015491516313b477c360e01b8152600481018b9052602481018a9052909291829182916001600160a01b0316906313b477c39060440160606040518083038186803b1580156122e257600080fd5b505afa1580156122f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231a91906156e7565b60008080526020889052604090206006015492955090935091508290612341908590615ce4565b61234b9190615cd0565b9850818385600060018152602001908152602001600020600601546123709190615ce4565b61237a9190615cd0565b989b989a50985050505050505050565b60008481526006602052604090206004810154859185916001600160a01b0316331480156123bb5750806005015482145b6123d75760405162461bcd60e51b81526004016108d190615ab4565b6123df611b61565b156123fc5760405162461bcd60e51b81526004016108d190615b02565b6002600154141561241f5760405162461bcd60e51b81526004016108d190615b86565b600260015561242d87614bd9565b600087815260066020908152604080832083805291829052808320600184529083206004820180549394929391928a92612468908490615cb8565b92505081905550868160040160008282546124839190615cb8565b925050819055508782600801600082825461249e9190615cb8565b92505081905550868160080160008282546124b99190615cb8565b9091555050600183015482546124de916001600160a01b03918216913391168b614ca3565b600183015481546124fe916001600160a01b03918216913391168a614ca3565b60408051898152602081018990528b918b9133917f2fa03a7689614e24be93be892ba0b8204d4e4619808144956932fe22175bc61e910160405180910390a45050600180555050505050505050565b600254604051631fe1defb60e11b81527fb3e53bff87a96979079674767cfa1a09f3cf2847ba695cbaae933c232f4bf7f09161010090046001600160a01b031690633fc3bdf6906125a490849033906004016159e0565b60206040518083038186803b1580156125bc57600080fd5b505afa1580156125d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f4919061553b565b6126105760405162461bcd60e51b81526004016108d190615a8e565b611a24614d0e565b6000808360028061263b8360009081526006602052604090206007015460ff1690565b600381111561265a57634e487b7160e01b600052602160045260246000fd5b146126775760405162461bcd60e51b81526004016108d190615b2c565b6000868152600660205260408082206001810154915163058dd4b160e51b8152600481018a90529092916001600160a01b03169063b1ba962090602401604080518083038186803b1580156126cb57600080fd5b505afa1580156126df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612703919061555b565b600080805260208590526040902060060154909250829150612726908990615ce4565b6127309190615cd0565b9550808783600060018152602001908152602001600020600601546127559190615ce4565b61275f9190615cd0565b9450505050509250929050565b6000600260015414156127915760405162461bcd60e51b81526004016108d190615b86565b60026001556127a1838333614222565b600180559392505050565b6127b461539d565b600082815260066020526040808220815160028082526060820190935290928392909190816020015b61283e60405180610120016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816127dd57505060008080526020848152604080832081516101208101835281546001600160a01b039081168252600183015416938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e0830152600801546101008201528251929350918391906128ef57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101919091526001600081815284835260409081902081516101208101835281546001600160a01b0390811682528285015416948101949094526002810154918401919091526003810154606084015260048101546080840152600581015460a0840152600681015460c0840152600781015460e0840152600801546101008301528251839190811061299b57634e487b7160e01b600052603260045260246000fd5b602090810291909101810191909152604080516101608101825287815291820183905260018501546001600160a01b039081169183019190915260028501548116606083015260038086015482166080840152600486015490911660a0830152600685015460c0830152600785015460e083019160ff90911690811115612a3257634e487b7160e01b600052602160045260246000fd5b8152602001846008015481526020018460090154815260200184600a01548152509350505050919050565b6000611bf6611b61565b612a6f61539d565b6001600160a01b038216600090815260076020526040902054612a91906127ac565b92915050565b60008281526006602052604090206003015482906001600160a01b03163314612ad25760405162461bcd60e51b81526004016108d190615ab4565b82600080612af28360009081526006602052604090206007015460ff1690565b6003811115612b1157634e487b7160e01b600052602160045260246000fd5b14612b2e5760405162461bcd60e51b81526004016108d190615b2c565b600354841115612b6b5760405162461bcd60e51b81526020600482015260086024820152670a8dede40d0d2ced60c31b60448201526064016108d1565b600085815260066020908152604091829020600b8101879055915186815287917f24867dfb6fcb9970a07be21024956524abe7a1837faa903ff0e99aaa40cf893e910160405180910390a2505050505050565b600080612bc9611b61565b15612be65760405162461bcd60e51b81526004016108d190615b02565b60026001541415612c095760405162461bcd60e51b81526004016108d190615b86565b6002600155600085815260066020526040902060048101548691906001600160a01b031680158015612c47575060038201546001600160a01b031633145b80612c5a5750336001600160a01b038216145b612c765760405162461bcd60e51b81526004016108d190615ab4565b612c818860036148e5565b600088815260066020908152604080832083805291829052808320600180855291909320908201549192916001600160a01b03166305c008428c612cc58686613e67565b6040516001600160e01b031960e085901b16815260048101929092526024820152604481018d9052606481018c90526084016040805180830381600087803b158015612d1057600080fd5b505af1158015612d24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4891906156c4565b600783810191909155830155612d5e838c614d68565b816007016000828254612d719190615d03565b9091555050600780830154908201546040518d927f87efe79f362036cc4820341f6a35939a512b18c3432c5e367a6cfd09d41d748392612db992918252602082015260400190565b60405180910390a260079182015491015460018055909a909950975050505050505050565b606060086000612ded82614e88565b905080612e2f576040805160008082526020820190925290612e25565b612e1261539d565b815260200190600190039081612e0a5790505b5092505050612a91565b838111612e4457612e41600182615d03565b93505b84612e50856001615cb8565b612e5a9190615d03565b67ffffffffffffffff811115612e8057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612eb957816020015b612ea661539d565b815260200190600190039081612e9e5790505b509250845b848111612f1057612ed26106d18483614e92565b848281518110612ef257634e487b7160e01b600052603260045260246000fd5b60200260200101819052508080612f0890615d46565b915050612ebe565b50505092915050565b600080612f24611b61565b15612f415760405162461bcd60e51b81526004016108d190615b02565b60026001541415612f645760405162461bcd60e51b81526004016108d190615b86565b60026001819055849080612f8a8360009081526006602052604090206007015460ff1690565b6003811115612fa957634e487b7160e01b600052602160045260246000fd5b14612fc65760405162461bcd60e51b81526004016108d190615b2c565b600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c919061553b565b6130685760405162461bcd60e51b81526004016108d190615b57565b6000868152600660205260408120906130818888612222565b60008080526020869052604090206003015492985090965091506130a59087614e9e565b60016000908152602083905260409020600301546130c39086614e9e565b600080805260208390526040812060060180548892906130e4908490615cb8565b909155505060016000908152602083905260408120600601805487929061310c908490615cb8565b9091555050600080805260208390526040908190206001015490516340c10f1960e01b81526001600160a01b03909116906340c10f19906131539033908a90600401615966565b600060405180830381600087803b15801561316d57600080fd5b505af1158015613181573d6000803e3d6000fd5b50506001600081815260208690526040908190209091015490516340c10f1960e01b81526001600160a01b0390911692506340c10f1991506131c99033908990600401615966565b600060405180830381600087803b1580156131e357600080fd5b505af11580156131f7573d6000803e3d6000fd5b505050600183015461321991506001600160a01b03838116913391168a614ca3565b600182015460405163201ae4c360e11b8152600481018a9052602481018990526001600160a01b0390911690634035c98690604401600060405180830381600087803b15801561326857600080fd5b505af115801561327c573d6000803e3d6000fd5b5050604080518a8152602081018a90529081018890528a92503391507fba14bf69e87e8b55eaadf9fc7d147cdd2842ea4290b23cf0a8d6c6985e208ab89060600160405180910390a3505060018055509194909350915050565b600260015414156132f95760405162461bcd60e51b81526004016108d190615b86565b600260015561330882826140ef565b600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b15801561335657600080fd5b505afa15801561336a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061338e9190615588565b6001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133c857600080fd5b505af11580156133dc573d6000803e3d6000fd5b50505050506133ed82823430614601565b505060018055565b600080613400611b61565b1561341d5760405162461bcd60e51b81526004016108d190615b02565b600260015414156134405760405162461bcd60e51b81526004016108d190615b86565b600260018190558490806134668360009081526006602052604090206007015460ff1690565b600381111561348557634e487b7160e01b600052602160045260246000fd5b146134a25760405162461bcd60e51b81526004016108d190615b2c565b60008681526006602052604090206004810154879187916001600160a01b0316331480156134d35750806005015482145b6134ef5760405162461bcd60e51b81526004016108d190615ab4565b60008981526006602090815260408083208380529182905280832060018452922090919061351c82614eea565b995061352781614eea565b985089156135965760018201546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906135639033908e90600401615966565b600060405180830381600087803b15801561357d57600080fd5b505af1158015613591573d6000803e3d6000fd5b505050505b88156136035760018101546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906135d09033908d90600401615966565b600060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050505b898260080154111561369b578260010160009054906101000a90046001600160a01b03166001600160a01b031663320636c58d6000338e87600801546136499190615d03565b6040518563ffffffff1660e01b81526004016136689493929190615bd0565b600060405180830381600087803b15801561368257600080fd5b505af1158015613696573d6000803e3d6000fd5b505050505b88816008015411156137265760018084015460088301546001600160a01b039091169163320636c5918f919033906136d4908f90615d03565b6040518563ffffffff1660e01b81526004016136f39493929190615bd0565b600060405180830381600087803b15801561370d57600080fd5b505af1158015613721573d6000803e3d6000fd5b505050505b604080518b8152602081018b90528d918d9133917fb912419c42ac1a2dc0fea182b90bb3845f7172adf699c1885218430804ccbc19910160405180910390a45050505050505050600180819055509250929050565b600254604051631fe1defb60e11b81527f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19161010090046001600160a01b031690633fc3bdf6906137d290849033906004016159e0565b60206040518083038186803b1580156137ea57600080fd5b505afa1580156137fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613822919061553b565b61383e5760405162461bcd60e51b81526004016108d190615a8e565b600580546001600160a01b0319166001600160a01b0384169081179091556040517f0ce1fe3d69e33a3738cb430bb204dd45ddd44f7fea080a9a051a30dc8084bc4b90600090a25050565b60058101546008820154600091908082116138a5576000610ce0565b610ce08183615d03565b6001820180546000918291806138c6575050613b11565b60006138d28387614f05565b90508082141561391b57866138e8600184615d03565b8154811061390657634e487b7160e01b600052603260045260246000fd5b90600052602060002001549450505050613b11565b600083828154811061393d57634e487b7160e01b600052603260045260246000fd5b90600052602060002001549050868114156139ca5787600001828154811061397557634e487b7160e01b600052603260045260246000fd5b60009182526020909120015495508588613990600186615d03565b815481106139ae57634e487b7160e01b600052603260045260246000fd5b90600052602060002001546139c39190615d03565b9450613b0c565b600082116139d9576000613a0f565b876139e5600184615d03565b81548110613a0357634e487b7160e01b600052603260045260246000fd5b90600052602060002001545b9550600086896000018481548110613a3757634e487b7160e01b600052603260045260246000fd5b9060005260206000200154613a4c9190615d03565b905087613a598284615d03565b1015613ac75781613a6a8983615cb8565b613a749190615d03565b613a7e9088615cb8565b96508689613a8d600187615d03565b81548110613aab57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154613ac09190615d03565b9550613b0a565b8689613ad4600187615d03565b81548110613af257634e487b7160e01b600052603260045260246000fd5b9060005260206000200154613b079190615d03565b95505b505b505050505b9250929050565b600080613b23611b61565b15613b405760405162461bcd60e51b81526004016108d190615b02565b84600280613b608360009081526006602052604090206007015460ff1690565b6003811115613b7f57634e487b7160e01b600052602160045260246000fd5b14613b9c5760405162461bcd60e51b81526004016108d190615b2c565b6000878152600660205260408120908181896001811115613bcd57634e487b7160e01b600052602160045260246000fd5b6001811115613bec57634e487b7160e01b600052602160045260246000fd5b81526020808201929092526040908101600090812060018101546001600160a01b03168083526004855283832033845290945291902060028101549193509060ff1615613c6d5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b60448201526064016108d1565b60018401546001600160a01b0316613c8e613c8785613889565b83906138af565b90995097508715613cfe5760405163320636c560e01b81526001600160a01b0382169063320636c590613ccb908f908f908f908e90600401615bd0565b600060405180830381600087803b158015613ce557600080fd5b505af1158015613cf9573d6000803e3d6000fd5b505050505b600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b158015613d4c57600080fd5b505afa158015613d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d84919061553b565b15613dea576040516340c10f1960e01b81526001600160a01b038416906340c10f1990613db79033908d90600401615966565b600060405180830381600087803b158015613dd157600080fd5b505af1158015613de5573d6000803e3d6000fd5b505050505b60028201805460ff191660019081179091558b90811115613e1b57634e487b7160e01b600052602160045260246000fd5b604080518b8152602081018b90528e9133917f7708755c9b641bf197be5047b04002d2e88fa658c173a351067747eb5dfc568a910160405180910390a450505050505050935093915050565b600060035483600601548360060154613e809190615ce4565b613e8a9190615cd0565b9392505050565b60005b82811015610eaf576000828281518110613ebe57634e487b7160e01b600052603260045260246000fd5b602002602001015190508060001415613f8457848483818110613ef157634e487b7160e01b600052603260045260246000fd5b9050602002016020810190613f069190615407565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613f319190615952565b60206040518083038186803b158015613f4957600080fd5b505afa158015613f5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f8191906155f5565b90505b613fce3382878786818110613fa957634e487b7160e01b600052603260045260246000fd5b9050602002016020810190613fbe9190615407565b6001600160a01b03169190614fe4565b5080613fd981615d46565b915050613e94565b6000613e8a8383615003565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b038116612a915760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016108d1565b61408f611b61565b6140ab5760405162461bcd60e51b81526004016108d190615a38565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516140e59190615952565b60405180910390a1565b600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b15801561413d57600080fd5b505afa158015614151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141759190615588565b6001600160a01b0316614187836127ac565b602001518260018111156141ab57634e487b7160e01b600052602160045260246000fd5b815181106141c957634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b03161461421e5760405162461bcd60e51b815260206004820152601060248201526f139bdd08185b88115512081d985d5b1d60821b60448201526064016108d1565b5050565b600061422c611b61565b156142495760405162461bcd60e51b81526004016108d190615b02565b836003806142698360009081526006602052604090206007015460ff1690565b600381111561428857634e487b7160e01b600052602160045260246000fd5b146142a55760405162461bcd60e51b81526004016108d190615b2c565b60008681526006602052604081209081818860018111156142d657634e487b7160e01b600052602160045260246000fd5b60018111156142f557634e487b7160e01b600052602160045260246000fd5b8152602001908152602001600020905061430f8888610991565b600185015460025460408051630afe914160e21b81529051939b506001600160a01b0392831696506101009091049091169350632bfa45049250600480820192602092909190829003018186803b15801561436957600080fd5b505afa15801561437d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143a1919061553b565b15614490576040516370a0823160e01b81526000906001600160a01b038316906370a08231906143d5903390600401615952565b60206040518083038186803b1580156143ed57600080fd5b505afa158015614401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061442591906155f5565b9050801561448e57604051632770a7eb60e21b81526001600160a01b03831690639dc29fac9061445b9033908590600401615966565b600060405180830381600087803b15801561447557600080fd5b505af1158015614489573d6000803e3d6000fd5b505050505b505b600183015482546144af916001600160a01b0391821691168989614ca3565b6001828101546001600160a01b031660009081526004602090815260408083203384529091529020600201805461ff001916610100179055889081111561450657634e487b7160e01b600052602160045260246000fd5b6040518781528a9033907f84557df06a9cf3a49d0c3fb7e6ed5a54d316659c8d62d269901c3dfccf741fd89060200160405180910390a450505050509392505050565b604080516000808252602082019092526001600160a01b0384169083906040516145739190615936565b60006040518083038185875af1925050503d80600081146145b0576040519150601f19603f3d011682016040523d82523d6000602084013e6145b5565b606091505b50509050806145fc5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016108d1565b505050565b614609611b61565b156146265760405162461bcd60e51b81526004016108d190615b02565b61462f84614bd9565b600084815260066020526040812060018082015491926146bc9285926001600160a01b039091169187918691908a9081111561467b57634e487b7160e01b600052602160045260246000fd5b600181111561469a57634e487b7160e01b600052602160045260246000fd5b81526020810191909152604001600020546001600160a01b0316929190614ca3565b60008382828760018111156146e157634e487b7160e01b600052602160045260246000fd5b600181111561470057634e487b7160e01b600052602160045260246000fd5b815260200190815260200160002060040160008282546147209190615cb8565b9182905550915060009050600481848189600181111561475057634e487b7160e01b600052602160045260246000fd5b600181111561476f57634e487b7160e01b600052602160045260246000fd5b815260208082019290925260409081016000908120600101546001600160a01b031684528383019490945291820183203384529052812080549092506147b557856147fa565b8154869083906147c790600190615d03565b815481106147e557634e487b7160e01b600052603260045260246000fd5b90600052602060002001546147fa9190615cb8565b905061485984600089600181111561482257634e487b7160e01b600052602160045260246000fd5b600181111561484157634e487b7160e01b600052602160045260246000fd5b81526020019081526020016000206003015482614e9e565b600180830180548083018255600091825260208083209091018690558454808401865585835291200182905587908111156148a457634e487b7160e01b600052602160045260246000fd5b604051878152899033907f91ede45f04a37a7c170f5c1207df3b6bc748dc1e04ad5e917a241d0f52feada39060200160405180910390a45050505050505050565b6000828152600660205260409020600781015460ff16600283600381111561491d57634e487b7160e01b600052602160045260246000fd5b141561498b57600181600381111561494557634e487b7160e01b600052602160045260246000fd5b146149625760405162461bcd60e51b81526004016108d190615b2c565b42826009015411156149865760405162461bcd60e51b81526004016108d190615adc565b614a19565b60028160038111156149ad57634e487b7160e01b600052602160045260246000fd5b1480156149d9575060038360038111156149d757634e487b7160e01b600052602160045260246000fd5b145b6149f55760405162461bcd60e51b81526004016108d190615b2c565b4282600a01541115614a195760405162461bcd60e51b81526004016108d190615adc565b60078201805484919060ff19166001836003811115614a4857634e487b7160e01b600052602160045260246000fd5b021790555050505050565b60008080526020859052604090206004810154600290910154819015614ab557614ab282876000805b6001811115614a9b57634e487b7160e01b600052602160045260246000fd5b815260200190815260200160002060020154615052565b90505b600160009081526020879052604090206004810154600290910154819015614ae857614ae5828960006001614a7c565b90505b60018801546001600160a01b0316634c905348888584614b08828a615d03565b614b128789615d03565b6040516001600160e01b031960e088901b1681526004810195909552602485019390935260448401919091526064830152608482015260a4810189905260c4810188905260e4016040805180830381600087803b158015614b7257600080fd5b505af1158015614b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614baa91906156c4565b600080805260209a909a526040808b2060018c529a206005908101919091559098019790975550505050505050565b600081815260066020526040812090600782015460ff166003811115614c0f57634e487b7160e01b600052602160045260246000fd5b1415614c5d5760008160080154118015614c2d575042816008015411155b614c495760405162461bcd60e51b81526004016108d190615adc565b60078101805460ff1916600117905561421e565b6001600782015460ff166003811115614c8657634e487b7160e01b600052602160045260246000fd5b1461421e5760405162461bcd60e51b81526004016108d190615b2c565b6040516001600160a01b0380851660248301528316604482015260648101829052610eaf9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152615068565b614d16611b61565b15614d335760405162461bcd60e51b81526004016108d190615b02565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586140d83390565b6005546000906001600160a01b031615612a91576001600090815260208490526040812060035460068087015490830154929392614da69190615ce4565b614db09190615cd0565b90508082600701541115614e8057600354818360070154614dd19190615d03565b86600b0154614de09190615ce4565b614dea9190615cd0565b60018601546005548454929550614e11926001600160a01b03908116928116911686614ca3565b600554825460405163c56d414b60e01b8152600481018790526001600160a01b0391821660248201526044810186905291169063c56d414b90606401600060405180830381600087803b158015614e6757600080fd5b505af1158015614e7b573d6000803e3d6000fd5b505050505b505092915050565b6000612a91825490565b6000613e8a838361513a565b811580614eab5750818111155b61421e5760405162461bcd60e51b815260206004820152601060248201526f0457863656564732075736572206361760841b60448201526064016108d1565b6005810154600882015460009190808211613e8a5781610ce0565b8154600090614f1657506000612a91565b82546000905b80821015614f80576000614f3083836151ce565b905084868281548110614f5357634e487b7160e01b600052603260045260246000fd5b90600052602060002001541115614f6c57809150614f7a565b614f77816001615cb8565b92505b50614f1c565b600082118015614fc357508385614f98600185615d03565b81548110614fb657634e487b7160e01b600052603260045260246000fd5b9060005260206000200154145b15614fdc57614fd3600183615d03565b92505050612a91565b509050612a91565b6145fc8363a9059cbb60e01b8484604051602401614cd7929190615966565b600081815260018301602052604081205461504a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612a91565b506000612a91565b60008183106150615781613e8a565b5090919050565b60006150bd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166152259092919063ffffffff16565b8051909150156145fc57808060200190518101906150db919061553b565b6145fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108d1565b815460009082106151985760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b60648201526084016108d1565b8260000182815481106151bb57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b600060026151dc8184615d61565b6151e7600286615d61565b6151f19190615cb8565b6151fb9190615cd0565b615206600284615cd0565b615211600286615cd0565b61521b9190615cb8565b613e8a9190615cb8565b6060615234848460008561523c565b949350505050565b60608247101561529d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108d1565b843b6152eb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d1565b600080866001600160a01b031685876040516153079190615936565b60006040518083038185875af1925050503d8060008114615344576040519150601f19603f3d011682016040523d82523d6000602084013e615349565b606091505b5091509150615359828286615364565b979650505050505050565b60608315615373575081613e8a565b8251156153835782518084602001fd5b8160405162461bcd60e51b81526004016108d19190615a05565b604080516101608101825260008082526060602083018190529282018190529181018290526080810182905260a0810182905260c081018290529060e082019081526020016000815260200160008152602001600081525090565b803560028110610ce557600080fd5b600060208284031215615418578081fd5b8135613e8a81615dcd565b600080600060408486031215615437578182fd5b833567ffffffffffffffff8082111561544e578384fd5b818601915086601f830112615461578384fd5b81358181111561546f578485fd5b602088818360051b8601011115615484578586fd5b80840196508195508088013593508284111561549e578485fd5b838801935088601f8501126154b1578485fd5b83359150828211156154c5576154c5615db7565b8160051b604051601f19603f830116810181811086821117156154ea576154ea615db7565b604052838152828101945085830182870184018c1015615508578788fd5b8796505b8487101561552a57803586526001969096019594830194830161550c565b508096505050505050509250925092565b60006020828403121561554c578081fd5b81518015158114613e8a578182fd5b6000806040838503121561556d578182fd5b825161557881615dcd565b6020939093015192949293505050565b600060208284031215615599578081fd5b8151613e8a81615dcd565b6000602082840312156155b5578081fd5b813567ffffffffffffffff8111156155cb578182fd5b82016102008185031215613e8a578182fd5b6000602082840312156155ee578081fd5b5035919050565b600060208284031215615606578081fd5b5051919050565b600080600060608486031215615621578283fd5b83359250602084013561563381615dcd565b929592945050506040919091013590565b60008060408385031215615656578182fd5b82359150615666602084016153f8565b90509250929050565b600080600060608486031215615683578283fd5b83359250615693602085016153f8565b9150604084013590509250925092565b600080604083850312156156b5578182fd5b50508035926020909101359150565b600080604083850312156156d6578182fd5b505080516020909101519092909150565b6000806000606084860312156156fb578081fd5b8351925060208401519150604084015161571481615dcd565b809150509250925092565b600080600060608486031215615733578081fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561575f578182fd5b5050823594602084013594506040840135936060013592509050565b6000815180845260208085019450808401835b8381101561581857815180516001600160a01b03168852838101516157bd858a01826001600160a01b03169052565b5060408181015190890152606080820151908901526080808201519089015260a0808201519089015260c0808201519089015260e080820151908901526101009081015190880152610120909601959082019060010161578e565b509495945050505050565b6004811061583357615833615da1565b9052565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60006101608251845260208301518160208601526158818286018261577b565b915050604083015161589e60408601826001600160a01b03169052565b5060608301516158b960608601826001600160a01b03169052565b5060808301516158d460808601826001600160a01b03169052565b5060a08301516158ef60a08601826001600160a01b03169052565b5060c083015160c085015260e083015161590c60e0860182615823565b50610100838101519085015261012080840151908501526101409283015192909301919091525090565b60008251615948818460208701615d1a565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6000602080830181845280855180835260408601915060408160051b8701019250838701855b828110156159d357603f198886030184526159c1858351615861565b945092850192908501906001016159a5565b5092979650505050505050565b9182526001600160a01b0316602082015260400190565b60208101612a918284615823565b6000602082528251806020840152615a24816040850160208701615d1a565b601f01601f19169190910160400192915050565b60208082526014908201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604082015260600190565b6020808252600e908201526d125b9d985b1a59081d185c99d95d60921b604082015260600190565b6020808252600c908201526b155b985d5d1a1bdc9a5e995960a21b604082015260600190565b6020808252600e908201526d24b73b30b634b21031b0b63632b960911b604082015260600190565b6020808252600c908201526b139bdd081d1a5b59481e595d60a21b604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b60208082526011908201527024b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6020808252601590820152745661756c7420746f6b656e7320696e61637469766560581b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208252613e8a6020830184615861565b8481526080810160028510615be757615be7615da1565b60208201949094526001600160a01b03929092166040830152606090910152919050565b600087825260806020830152615c25608083018789615837565b8281036040840152615c38818688615837565b91505060018060a01b0383166060830152979650505050505050565b92835260208301919091526001600160a01b0316604082015260600190565b6000808335601e19843603018112615c89578283fd5b83018035915067ffffffffffffffff821115615ca3578283fd5b602001915036819003821315613b1157600080fd5b60008219821115615ccb57615ccb615d75565b500190565b600082615cdf57615cdf615d8b565b500490565b6000816000190483118215151615615cfe57615cfe615d75565b500290565b600082821015615d1557615d15615d75565b500390565b60005b83811015615d35578181015183820152602001615d1d565b83811115610eaf5750506000910152565b6000600019821415615d5a57615d5a615d75565b5060010190565b600082615d7057615d70615d8b565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611a2457600080fdfea26469706673582212206f83520e73186e0d34ea28fcdd1adc14b68191e5363c32ce7275b80258e966a264736f6c6343000803003300000000000000000000000047d1f3fda174270244a1d800c49f3af456f0500400000000000000000000000051f07e597a2a7de7601767407a45fb3f581f7b7d
Deployed Bytecode
0x6080604052600436106101ee5760003560e01c806379aba36d1161011357806396ce0795116100ab578063b98cca371161006f578063b98cca371461076e578063c7c311371461079b578063cdce1bef146107bb578063d066a4fa146107ce578063fdbb3aea146107ee576102a9565b806396ce0795146106e3578063b187bd26146106f9578063b1e3a9411461070e578063b4260cbc1461072e578063b81922051461074e576102a9565b806379aba36d146105ad5780637b103999146105cd5780637c61494d146105f25780637debdea6146106215780638456cb59146106415780638be74d96146106565780638f6175d114610676578063903d42961461069657806394708776146106b6576102a9565b80634011b97a116101865780634011b97a1461043c57806344c9af281461046957806351df78b4146104a95780635ab1bd53146104c95780635c975abb146104ed5780635ea171981461050257806360798cab1461054d578063674a8c551461056d578063795191ed1461058d576102a9565b806317d965e4146102ae57806327ac373a146102ce5780632faf3ea6146103135780633619b4641461034857806339443b8e146103765780633b1c91c7146103a65780633bf8d620146103e75780633f3d8fe7146104075780633f4ba83a14610427576102a9565b366102a957600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b15801561024157600080fd5b505afa158015610255573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102799190615588565b6001600160a01b0316336001600160a01b0316146102a757634e487b7160e01b600052600160045260246000fd5b005b600080fd5b3480156102ba57600080fd5b506102a76102c936600461560d565b61080e565b3480156102da57600080fd5b506102ee6102e9366004615644565b610991565b6040805194855260208501939093529183015260608201526080015b60405180910390f35b34801561031f57600080fd5b5061033361032e366004615644565b610c74565b6040805192835260208301919091520161030a565b34801561035457600080fd5b506103686103633660046155dd565b610cbc565b60405190815260200161030a565b34801561038257600080fd5b506103966103913660046155dd565b610cea565b604051901515815260200161030a565b3480156103b257600080fd5b506103da7f00000000000000000000000051f07e597a2a7de7601767407a45fb3f581f7b7d81565b60405161030a9190615952565b3480156103f357600080fd5b506102a7610402366004615423565b610d77565b34801561041357600080fd5b506103686104223660046155a4565b610eb5565b34801561043357600080fd5b506102a7611959565b34801561044857600080fd5b50610368610457366004615407565b60076020526000908152604090205481565b34801561047557600080fd5b5061049c6104843660046155dd565b60009081526006602052604090206007015460ff1690565b60405161030a91906159f7565b3480156104b557600080fd5b506103686104c4366004615644565b611a27565b3480156104d557600080fd5b506103da60025461010090046001600160a01b031690565b3480156104f957600080fd5b50610396611b61565b34801561050e57600080fd5b5061033361051d3660046155dd565b60009081526006602090815260408083208380529091528082206003908101546001845291909220909101549091565b34801561055957600080fd5b506102a761056836600461566f565b611bfb565b34801561057957600080fd5b50610333610588366004615644565b611c38565b34801561059957600080fd5b506103336105a83660046156a3565b611d6f565b3480156105b957600080fd5b506103336105c836600461571f565b6120c0565b3480156105d957600080fd5b506002546103da9061010090046001600160a01b031681565b3480156105fe57600080fd5b5061061261060d3660046156a3565b612222565b60405161030a93929190615c54565b34801561062d57600080fd5b506102a761063c36600461574a565b61238a565b34801561064d57600080fd5b506102a761254d565b34801561066257600080fd5b506005546103da906001600160a01b031681565b34801561068257600080fd5b506103336106913660046156a3565b612618565b3480156106a257600080fd5b506103686106b1366004615644565b61276c565b3480156106c257600080fd5b506106d66106d13660046155dd565b6127ac565b60405161030a9190615bbd565b3480156106ef57600080fd5b5061036860035481565b34801561070557600080fd5b50610396612a5d565b34801561071a57600080fd5b506106d6610729366004615407565b612a67565b34801561073a57600080fd5b506102a76107493660046156a3565b612a97565b34801561075a57600080fd5b5061033361076936600461571f565b612bbe565b34801561077a57600080fd5b5061078e6107893660046156a3565b612dde565b60405161030a919061597f565b3480156107a757600080fd5b506103336107b63660046156a3565b612f19565b6102a76107c9366004615644565b6132d6565b3480156107da57600080fd5b506103336107e93660046156a3565b6133f5565b3480156107fa57600080fd5b506102a7610809366004615407565b61377b565b600254604051631fe1defb60e11b81527ff0983e2b51e2b2ff224c42b1eabc9a0c5025d7bfb63557cd50ce5287048e68089161010090046001600160a01b031690633fc3bdf69061086590849033906004016159e0565b60206040518083038186803b15801561087d57600080fd5b505afa158015610891573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b5919061553b565b6108da5760405162461bcd60e51b81526004016108d190615a8e565b60405180910390fd5b600084815260066020526040902060048101546001600160a01b0316156109365760048101546001600160a01b03163314801561091a5750806005015483145b6109365760405162461bcd60e51b81526004016108d190615ab4565b6004810180546001600160a01b0319166001600160a01b03861690811790915560058201849055604051869185917fd7d4fa7e0ef0027fb55099898c747a0fe2ad536a3d2450103bc133e1f646b75890600090a45050505050565b60008281526006602052604081208190819081908190818760018111156109c857634e487b7160e01b600052602160045260246000fd5b60018111156109e757634e487b7160e01b600052602160045260246000fd5b81526020808201929092526040908101600090812060018101546001600160a01b031682526004845282822033835290935220600281015491925090610100900460ff16610c6957610a42610a3b83613889565b82906138af565b6002830154919750945060ff16610ae95760018201546040516370a0823160e01b81528796506001600160a01b03909116906370a0823190610a88903390600401615952565b60206040518083038186803b158015610aa057600080fd5b505afa158015610ab4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad891906155f5565b610ae29087615cb8565b9550610bfd565b60009350600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b158015610b3b57600080fd5b505afa158015610b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b73919061553b565b15610bfd5760018201546040516370a0823160e01b81526001600160a01b03909116906370a0823190610baa903390600401615952565b60206040518083038186803b158015610bc257600080fd5b505afa158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa91906155f5565b95505b600360008981526006602052604090206007015460ff166003811115610c3357634e487b7160e01b600052602160045260246000fd5b1415610c6957600094508160060154868360070154610c529190615ce4565b610c5c9190615cd0565b610c669085615cb8565b92505b505092959194509250565b60008060026001541415610c9a5760405162461bcd60e51b81526004016108d190615b86565b6002600155610caa848433613b18565b915091505b6001805590939092509050565b6000818152600660209081526040808320838052918290528220610ce08282613e67565b925050505b919050565b600081815260066020526040812081600782015460ff166003811115610d2057634e487b7160e01b600052602160045260246000fd5b1415610d465742816008015411158015610d3e575060008160080154115b915050610ce5565b6001600782015460ff166003811115610d6f57634e487b7160e01b600052602160045260246000fd5b149392505050565b610d7f611b61565b610d9b5760405162461bcd60e51b81526004016108d190615a38565b600254604051631fe1defb60e11b81527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50419161010090046001600160a01b031690633fc3bdf690610df290849033906004016159e0565b60206040518083038186803b158015610e0a57600080fd5b505afa158015610e1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e42919061553b565b610e5e5760405162461bcd60e51b81526004016108d190615a8e565b81518314610ea45760405162461bcd60e51b8152602060048201526013602482015272496e76616c69642061727261792073697a657360681b60448201526064016108d1565b610eaf848484613e91565b50505050565b6000610ebf611b61565b15610edc5760405162461bcd60e51b81526004016108d190615b02565b600254604051631fe1defb60e11b81527f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f9161010090046001600160a01b031690633fc3bdf690610f3390849033906004016159e0565b60206040518083038186803b158015610f4b57600080fd5b505afa158015610f5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f83919061553b565b610f9f5760405162461bcd60e51b81526004016108d190615a8e565b60026001541415610fc25760405162461bcd60e51b81526004016108d190615b86565b600260018190555461010090046001600160a01b0316633fc3bdf67f928286c473ded01ff8bf61a1986f14a0579066072fa8261442d9fea514d93a4c61100e6080870160608801615407565b6040518363ffffffff1660e01b815260040161102b9291906159e0565b60206040518083038186803b15801561104357600080fd5b505afa158015611057573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107b919061553b565b6110975760405162461bcd60e51b81526004016108d190615a66565b60025461010090046001600160a01b0316633fc3bdf67f17a8e30262c1f919c33056d877a3c22b95c2f5e4dac44683c1c2323cd79fbdb06110de6060870160408801615407565b6040518363ffffffff1660e01b81526004016110fb9291906159e0565b60206040518083038186803b15801561111357600080fd5b505afa158015611127573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061114b919061553b565b6111675760405162461bcd60e51b81526004016108d190615a66565b428360a0013510156111b05760405162461bcd60e51b8152602060048201526012602482015271496e76616c69642073746172742074696d6560701b60448201526064016108d1565b60008360c001351180156111c8575060008360e00135115b6112085760405162461bcd60e51b81526020600482015260116024820152704e6f207a65726f20696e74657276616c7360781b60448201526064016108d1565b6305f5e10083608001351061125a5760405162461bcd60e51b81526020600482015260186024820152774d6178696d756d20687572646c652069732031303030302560401b60448201526064016108d1565b826080013560035411156112a55760405162461bcd60e51b81526020600482015260126024820152714d696e20687572646c65206973203130302560701b60448201526064016108d1565b60006112b46020850185615407565b6001600160a01b0316141580156112e05750306112d46020850185615407565b6001600160a01b031614155b8015611305575060006112f96040850160208601615407565b6001600160a01b031614155b801561132957503061131d6040850160208601615407565b6001600160a01b031614155b6113455760405162461bcd60e51b81526004016108d190615a66565b600061135960c085013560a0860135615cb8565b9050600061136b60e086013583615cb8565b905060008061137d6020880188615407565b61138d6040890160208a01615407565b61139d60808a0160608b01615407565b604080516001600160a01b0394851660208201529284169083015290911660608201526080888101359082015260a0808901359082015260c0810185905260e081018490526101000160408051601f198184030181529190528051602090910120955061140b600887613fe1565b50600086815260066020526040902060038101546001600160a01b0316156114615760405162461bcd60e51b81526020600482015260096024820152684475706c696361746560b81b60448201526064016108d1565b6114716080890160608a01615407565b6001820180546001600160a01b03929092166001600160a01b0319928316179055600282018054909116331790556114af6060890160408a01615407565b6003820180546001600160a01b0319166001600160a01b039283161790556080890135600683015560a0890135600883015560098201869055600a8201859055600280546040516368e781c560e11b8152600481019290925261010090049091169063d1cf038a90602401600060405180830381600087803b15801561153457600080fd5b505af1158015611548573d6000803e3d6000fd5b505060408051600060208201529081018a90526115a292507f00000000000000000000000051f07e597a2a7de7601767407a45fb3f581f7b7d91506060015b60405160208183030381529060405280519060200120613fed565b92506115e57f00000000000000000000000051f07e597a2a7de7601767407a45fb3f581f7b7d600189604051602001611587929190918252602082015260400190565b91506115f46020890189615407565b6000808052602083815260409182902080546001600160a01b0319166001600160a01b03949094169390931790925561163291908a01908a01615407565b600160008181526020849052604080822080546001600160a01b03199081166001600160a01b0396871617909155828052908220830180549091169387169390931790925583918391815260208082019290925260409081016000908120600190810180546001600160a01b0319166001600160a01b039687161790558180528584528282206101808e01356002808301919091556101a08f01356003928301559183528383206101c08f0135928101929092556101e08e0135910155868416815260079092528082208a905591841681522087905560088101544214156117245760078101805460ff191660011790555b6117346080890160608a01615407565b6001600160a01b031663cc8fc76d8861175060208c018c615407565b61176060408d0160208e01615407565b6040516001600160e01b031960e086901b16815260048101939093526001600160a01b039182166024840152166044820152606401600060405180830381600087803b1580156117af57600080fd5b505af11580156117c3573d6000803e3d6000fd5b5050506001600160a01b0384169050636ebd362c886117e66101008c018c615c73565b6117f46101208e018e615c73565b306040518763ffffffff1660e01b815260040161181696959493929190615c0b565b600060405180830381600087803b15801561183057600080fd5b505af1158015611844573d6000803e3d6000fd5b5050506001600160a01b0383169050636ebd362c886118676101408c018c615c73565b6118756101608e018e615c73565b306040518763ffffffff1660e01b815260040161189796959493929190615c0b565b600060405180830381600087803b1580156118b157600080fd5b505af11580156118c5573d6000803e3d6000fd5b506118dc93505060408a0191505060208901615407565b6001600160a01b03166118f26020890189615407565b6001600160a01b0316877feea458d0f0292103cf6181411e8b3f4af6309892ec85eac3a3bf166cbce4d03d85856040516119429291906001600160a01b0392831681529116602082015260400190565b60405180910390a450506001805550919392505050565b600254604051631fe1defb60e11b81527f55435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a50419161010090046001600160a01b031690633fc3bdf6906119b090849033906004016159e0565b60206040518083038186803b1580156119c857600080fd5b505afa1580156119dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a00919061553b565b611a1c5760405162461bcd60e51b81526004016108d190615a8e565b611a24614087565b50565b600060026001541415611a4c5760405162461bcd60e51b81526004016108d190615b86565b6002600155611a5b83836140ef565b611a66838330614222565b9050600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b158015611ab657600080fd5b505afa158015611aca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aee9190615588565b6001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b8152600401611b1b91815260200190565b600060405180830381600087803b158015611b3557600080fd5b505af1158015611b49573d6000803e3d6000fd5b50505050611b573382614549565b6001805592915050565b6000600260019054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bb157600080fd5b505afa158015611bc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be9919061553b565b80611bf6575060025460ff165b905090565b60026001541415611c1e5760405162461bcd60e51b81526004016108d190615b86565b6002600155611c2f83838333614601565b50506001805550565b60008060026001541415611c5e5760405162461bcd60e51b81526004016108d190615b86565b6002600155611c6d84846140ef565b611c78848430613b18565b8092508193505050600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b158015611cce57600080fd5b505afa158015611ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d069190615588565b6001600160a01b0316632e1a7d4d826040518263ffffffff1660e01b8152600401611d3391815260200190565b600060405180830381600087803b158015611d4d57600080fd5b505af1158015611d61573d6000803e3d6000fd5b50505050610caf3382614549565b600080611d7a611b61565b15611d975760405162461bcd60e51b81526004016108d190615b02565b60026001541415611dba5760405162461bcd60e51b81526004016108d190615b86565b60026001819055849080611de08360009081526006602052604090206007015460ff1690565b6003811115611dff57634e487b7160e01b600052602160045260246000fd5b14611e1c5760405162461bcd60e51b81526004016108d190615b2c565b600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b158015611e6a57600080fd5b505afa158015611e7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea2919061553b565b611ebe5760405162461bcd60e51b81526004016108d190615b57565b6000868152600660205260409020611ed68787612618565b60008080526020849052604090819020600101549051632770a7eb60e21b81529297509095506001600160a01b031690639dc29fac90611f1c9033908990600401615966565b600060405180830381600087803b158015611f3657600080fd5b505af1158015611f4a573d6000803e3d6000fd5b5050600160008181526020859052604090819020909101549051632770a7eb60e21b81526001600160a01b039091169250639dc29fac9150611f929033908890600401615966565b600060405180830381600087803b158015611fac57600080fd5b505af1158015611fc0573d6000803e3d6000fd5b505060008080526020849052604081206006018054899450909250611fe6908490615d03565b909155505060016000908152602082905260408120600601805486929061200e908490615d03565b90915550506001810154604051637440ae0160e11b81526001600160a01b039091169063e8815c0290612049908a908a903390600401615c54565b600060405180830381600087803b15801561206357600080fd5b505af1158015612077573d6000803e3d6000fd5b50506040518881523392507fde0520231a263824b6834133aeea4afdd1408d02d31aabe77e8f3b625467c6ba915060200160405180910390a25050600180555090939092509050565b6000806120cb611b61565b156120e85760405162461bcd60e51b81526004016108d190615b02565b6002600154141561210b5760405162461bcd60e51b81526004016108d190615b86565b6002600155600085815260066020526040902060048101548691906001600160a01b031680158015612149575060038201546001600160a01b031633145b8061215c5750336001600160a01b038216145b6121785760405162461bcd60e51b81526004016108d190615ab4565b6121838860026148e5565b600088815260066020526040902061219d818a8a8a614a53565b600080805260208281526040808320600184529281902060058085015460068087019182559183015491830182905554835190815293840152815190928d927f15294ad9d42e2bbd446d4ff6ca28fef807d1631ad53c688303fe468410830f3292918290030190a260069182015491015460018055909a909950975050505050505050565b60008080846002806122468360009081526006602052604090206007015460ff1690565b600381111561226557634e487b7160e01b600052602160045260246000fd5b146122825760405162461bcd60e51b81526004016108d190615b2c565b600087815260066020526040808220600181015491516313b477c360e01b8152600481018b9052602481018a9052909291829182916001600160a01b0316906313b477c39060440160606040518083038186803b1580156122e257600080fd5b505afa1580156122f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061231a91906156e7565b60008080526020889052604090206006015492955090935091508290612341908590615ce4565b61234b9190615cd0565b9850818385600060018152602001908152602001600020600601546123709190615ce4565b61237a9190615cd0565b989b989a50985050505050505050565b60008481526006602052604090206004810154859185916001600160a01b0316331480156123bb5750806005015482145b6123d75760405162461bcd60e51b81526004016108d190615ab4565b6123df611b61565b156123fc5760405162461bcd60e51b81526004016108d190615b02565b6002600154141561241f5760405162461bcd60e51b81526004016108d190615b86565b600260015561242d87614bd9565b600087815260066020908152604080832083805291829052808320600184529083206004820180549394929391928a92612468908490615cb8565b92505081905550868160040160008282546124839190615cb8565b925050819055508782600801600082825461249e9190615cb8565b92505081905550868160080160008282546124b99190615cb8565b9091555050600183015482546124de916001600160a01b03918216913391168b614ca3565b600183015481546124fe916001600160a01b03918216913391168a614ca3565b60408051898152602081018990528b918b9133917f2fa03a7689614e24be93be892ba0b8204d4e4619808144956932fe22175bc61e910160405180910390a45050600180555050505050505050565b600254604051631fe1defb60e11b81527fb3e53bff87a96979079674767cfa1a09f3cf2847ba695cbaae933c232f4bf7f09161010090046001600160a01b031690633fc3bdf6906125a490849033906004016159e0565b60206040518083038186803b1580156125bc57600080fd5b505afa1580156125d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f4919061553b565b6126105760405162461bcd60e51b81526004016108d190615a8e565b611a24614d0e565b6000808360028061263b8360009081526006602052604090206007015460ff1690565b600381111561265a57634e487b7160e01b600052602160045260246000fd5b146126775760405162461bcd60e51b81526004016108d190615b2c565b6000868152600660205260408082206001810154915163058dd4b160e51b8152600481018a90529092916001600160a01b03169063b1ba962090602401604080518083038186803b1580156126cb57600080fd5b505afa1580156126df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612703919061555b565b600080805260208590526040902060060154909250829150612726908990615ce4565b6127309190615cd0565b9550808783600060018152602001908152602001600020600601546127559190615ce4565b61275f9190615cd0565b9450505050509250929050565b6000600260015414156127915760405162461bcd60e51b81526004016108d190615b86565b60026001556127a1838333614222565b600180559392505050565b6127b461539d565b600082815260066020526040808220815160028082526060820190935290928392909190816020015b61283e60405180610120016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b8152602001906001900390816127dd57505060008080526020848152604080832081516101208101835281546001600160a01b039081168252600183015416938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a0830152600681015460c0830152600781015460e0830152600801546101008201528251929350918391906128ef57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101919091526001600081815284835260409081902081516101208101835281546001600160a01b0390811682528285015416948101949094526002810154918401919091526003810154606084015260048101546080840152600581015460a0840152600681015460c0840152600781015460e0840152600801546101008301528251839190811061299b57634e487b7160e01b600052603260045260246000fd5b602090810291909101810191909152604080516101608101825287815291820183905260018501546001600160a01b039081169183019190915260028501548116606083015260038086015482166080840152600486015490911660a0830152600685015460c0830152600785015460e083019160ff90911690811115612a3257634e487b7160e01b600052602160045260246000fd5b8152602001846008015481526020018460090154815260200184600a01548152509350505050919050565b6000611bf6611b61565b612a6f61539d565b6001600160a01b038216600090815260076020526040902054612a91906127ac565b92915050565b60008281526006602052604090206003015482906001600160a01b03163314612ad25760405162461bcd60e51b81526004016108d190615ab4565b82600080612af28360009081526006602052604090206007015460ff1690565b6003811115612b1157634e487b7160e01b600052602160045260246000fd5b14612b2e5760405162461bcd60e51b81526004016108d190615b2c565b600354841115612b6b5760405162461bcd60e51b81526020600482015260086024820152670a8dede40d0d2ced60c31b60448201526064016108d1565b600085815260066020908152604091829020600b8101879055915186815287917f24867dfb6fcb9970a07be21024956524abe7a1837faa903ff0e99aaa40cf893e910160405180910390a2505050505050565b600080612bc9611b61565b15612be65760405162461bcd60e51b81526004016108d190615b02565b60026001541415612c095760405162461bcd60e51b81526004016108d190615b86565b6002600155600085815260066020526040902060048101548691906001600160a01b031680158015612c47575060038201546001600160a01b031633145b80612c5a5750336001600160a01b038216145b612c765760405162461bcd60e51b81526004016108d190615ab4565b612c818860036148e5565b600088815260066020908152604080832083805291829052808320600180855291909320908201549192916001600160a01b03166305c008428c612cc58686613e67565b6040516001600160e01b031960e085901b16815260048101929092526024820152604481018d9052606481018c90526084016040805180830381600087803b158015612d1057600080fd5b505af1158015612d24573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d4891906156c4565b600783810191909155830155612d5e838c614d68565b816007016000828254612d719190615d03565b9091555050600780830154908201546040518d927f87efe79f362036cc4820341f6a35939a512b18c3432c5e367a6cfd09d41d748392612db992918252602082015260400190565b60405180910390a260079182015491015460018055909a909950975050505050505050565b606060086000612ded82614e88565b905080612e2f576040805160008082526020820190925290612e25565b612e1261539d565b815260200190600190039081612e0a5790505b5092505050612a91565b838111612e4457612e41600182615d03565b93505b84612e50856001615cb8565b612e5a9190615d03565b67ffffffffffffffff811115612e8057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612eb957816020015b612ea661539d565b815260200190600190039081612e9e5790505b509250845b848111612f1057612ed26106d18483614e92565b848281518110612ef257634e487b7160e01b600052603260045260246000fd5b60200260200101819052508080612f0890615d46565b915050612ebe565b50505092915050565b600080612f24611b61565b15612f415760405162461bcd60e51b81526004016108d190615b02565b60026001541415612f645760405162461bcd60e51b81526004016108d190615b86565b60026001819055849080612f8a8360009081526006602052604090206007015460ff1690565b6003811115612fa957634e487b7160e01b600052602160045260246000fd5b14612fc65760405162461bcd60e51b81526004016108d190615b2c565b600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b15801561301457600080fd5b505afa158015613028573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061304c919061553b565b6130685760405162461bcd60e51b81526004016108d190615b57565b6000868152600660205260408120906130818888612222565b60008080526020869052604090206003015492985090965091506130a59087614e9e565b60016000908152602083905260409020600301546130c39086614e9e565b600080805260208390526040812060060180548892906130e4908490615cb8565b909155505060016000908152602083905260408120600601805487929061310c908490615cb8565b9091555050600080805260208390526040908190206001015490516340c10f1960e01b81526001600160a01b03909116906340c10f19906131539033908a90600401615966565b600060405180830381600087803b15801561316d57600080fd5b505af1158015613181573d6000803e3d6000fd5b50506001600081815260208690526040908190209091015490516340c10f1960e01b81526001600160a01b0390911692506340c10f1991506131c99033908990600401615966565b600060405180830381600087803b1580156131e357600080fd5b505af11580156131f7573d6000803e3d6000fd5b505050600183015461321991506001600160a01b03838116913391168a614ca3565b600182015460405163201ae4c360e11b8152600481018a9052602481018990526001600160a01b0390911690634035c98690604401600060405180830381600087803b15801561326857600080fd5b505af115801561327c573d6000803e3d6000fd5b5050604080518a8152602081018a90529081018890528a92503391507fba14bf69e87e8b55eaadf9fc7d147cdd2842ea4290b23cf0a8d6c6985e208ab89060600160405180910390a3505060018055509194909350915050565b600260015414156132f95760405162461bcd60e51b81526004016108d190615b86565b600260015561330882826140ef565b600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b15801561335657600080fd5b505afa15801561336a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061338e9190615588565b6001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156133c857600080fd5b505af11580156133dc573d6000803e3d6000fd5b50505050506133ed82823430614601565b505060018055565b600080613400611b61565b1561341d5760405162461bcd60e51b81526004016108d190615b02565b600260015414156134405760405162461bcd60e51b81526004016108d190615b86565b600260018190558490806134668360009081526006602052604090206007015460ff1690565b600381111561348557634e487b7160e01b600052602160045260246000fd5b146134a25760405162461bcd60e51b81526004016108d190615b2c565b60008681526006602052604090206004810154879187916001600160a01b0316331480156134d35750806005015482145b6134ef5760405162461bcd60e51b81526004016108d190615ab4565b60008981526006602090815260408083208380529182905280832060018452922090919061351c82614eea565b995061352781614eea565b985089156135965760018201546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906135639033908e90600401615966565b600060405180830381600087803b15801561357d57600080fd5b505af1158015613591573d6000803e3d6000fd5b505050505b88156136035760018101546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906135d09033908d90600401615966565b600060405180830381600087803b1580156135ea57600080fd5b505af11580156135fe573d6000803e3d6000fd5b505050505b898260080154111561369b578260010160009054906101000a90046001600160a01b03166001600160a01b031663320636c58d6000338e87600801546136499190615d03565b6040518563ffffffff1660e01b81526004016136689493929190615bd0565b600060405180830381600087803b15801561368257600080fd5b505af1158015613696573d6000803e3d6000fd5b505050505b88816008015411156137265760018084015460088301546001600160a01b039091169163320636c5918f919033906136d4908f90615d03565b6040518563ffffffff1660e01b81526004016136f39493929190615bd0565b600060405180830381600087803b15801561370d57600080fd5b505af1158015613721573d6000803e3d6000fd5b505050505b604080518b8152602081018b90528d918d9133917fb912419c42ac1a2dc0fea182b90bb3845f7172adf699c1885218430804ccbc19910160405180910390a45050505050505050600180819055509250929050565b600254604051631fe1defb60e11b81527f71840dc4906352362b0cdaf79870196c8e42acafade72d5d5a6d59291253ceb19161010090046001600160a01b031690633fc3bdf6906137d290849033906004016159e0565b60206040518083038186803b1580156137ea57600080fd5b505afa1580156137fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613822919061553b565b61383e5760405162461bcd60e51b81526004016108d190615a8e565b600580546001600160a01b0319166001600160a01b0384169081179091556040517f0ce1fe3d69e33a3738cb430bb204dd45ddd44f7fea080a9a051a30dc8084bc4b90600090a25050565b60058101546008820154600091908082116138a5576000610ce0565b610ce08183615d03565b6001820180546000918291806138c6575050613b11565b60006138d28387614f05565b90508082141561391b57866138e8600184615d03565b8154811061390657634e487b7160e01b600052603260045260246000fd5b90600052602060002001549450505050613b11565b600083828154811061393d57634e487b7160e01b600052603260045260246000fd5b90600052602060002001549050868114156139ca5787600001828154811061397557634e487b7160e01b600052603260045260246000fd5b60009182526020909120015495508588613990600186615d03565b815481106139ae57634e487b7160e01b600052603260045260246000fd5b90600052602060002001546139c39190615d03565b9450613b0c565b600082116139d9576000613a0f565b876139e5600184615d03565b81548110613a0357634e487b7160e01b600052603260045260246000fd5b90600052602060002001545b9550600086896000018481548110613a3757634e487b7160e01b600052603260045260246000fd5b9060005260206000200154613a4c9190615d03565b905087613a598284615d03565b1015613ac75781613a6a8983615cb8565b613a749190615d03565b613a7e9088615cb8565b96508689613a8d600187615d03565b81548110613aab57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154613ac09190615d03565b9550613b0a565b8689613ad4600187615d03565b81548110613af257634e487b7160e01b600052603260045260246000fd5b9060005260206000200154613b079190615d03565b95505b505b505050505b9250929050565b600080613b23611b61565b15613b405760405162461bcd60e51b81526004016108d190615b02565b84600280613b608360009081526006602052604090206007015460ff1690565b6003811115613b7f57634e487b7160e01b600052602160045260246000fd5b14613b9c5760405162461bcd60e51b81526004016108d190615b2c565b6000878152600660205260408120908181896001811115613bcd57634e487b7160e01b600052602160045260246000fd5b6001811115613bec57634e487b7160e01b600052602160045260246000fd5b81526020808201929092526040908101600090812060018101546001600160a01b03168083526004855283832033845290945291902060028101549193509060ff1615613c6d5760405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e4818db185a5b5959608a1b60448201526064016108d1565b60018401546001600160a01b0316613c8e613c8785613889565b83906138af565b90995097508715613cfe5760405163320636c560e01b81526001600160a01b0382169063320636c590613ccb908f908f908f908e90600401615bd0565b600060405180830381600087803b158015613ce557600080fd5b505af1158015613cf9573d6000803e3d6000fd5b505050505b600260019054906101000a90046001600160a01b03166001600160a01b0316632bfa45046040518163ffffffff1660e01b815260040160206040518083038186803b158015613d4c57600080fd5b505afa158015613d60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d84919061553b565b15613dea576040516340c10f1960e01b81526001600160a01b038416906340c10f1990613db79033908d90600401615966565b600060405180830381600087803b158015613dd157600080fd5b505af1158015613de5573d6000803e3d6000fd5b505050505b60028201805460ff191660019081179091558b90811115613e1b57634e487b7160e01b600052602160045260246000fd5b604080518b8152602081018b90528e9133917f7708755c9b641bf197be5047b04002d2e88fa658c173a351067747eb5dfc568a910160405180910390a450505050505050935093915050565b600060035483600601548360060154613e809190615ce4565b613e8a9190615cd0565b9392505050565b60005b82811015610eaf576000828281518110613ebe57634e487b7160e01b600052603260045260246000fd5b602002602001015190508060001415613f8457848483818110613ef157634e487b7160e01b600052603260045260246000fd5b9050602002016020810190613f069190615407565b6001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613f319190615952565b60206040518083038186803b158015613f4957600080fd5b505afa158015613f5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f8191906155f5565b90505b613fce3382878786818110613fa957634e487b7160e01b600052603260045260246000fd5b9050602002016020810190613fbe9190615407565b6001600160a01b03169190614fe4565b5080613fd981615d46565b915050613e94565b6000613e8a8383615003565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528360601b60148201526e5af43d82803e903d91602b57fd5bf360881b6028820152826037826000f59150506001600160a01b038116612a915760405162461bcd60e51b8152602060048201526017602482015276115490cc4c4d8dce8818dc99585d194c8819985a5b1959604a1b60448201526064016108d1565b61408f611b61565b6140ab5760405162461bcd60e51b81526004016108d190615a38565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516140e59190615952565b60405180910390a1565b600260019054906101000a90046001600160a01b03166001600160a01b0316633fc8cef36040518163ffffffff1660e01b815260040160206040518083038186803b15801561413d57600080fd5b505afa158015614151573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141759190615588565b6001600160a01b0316614187836127ac565b602001518260018111156141ab57634e487b7160e01b600052602160045260246000fd5b815181106141c957634e487b7160e01b600052603260045260246000fd5b6020026020010151600001516001600160a01b03161461421e5760405162461bcd60e51b815260206004820152601060248201526f139bdd08185b88115512081d985d5b1d60821b60448201526064016108d1565b5050565b600061422c611b61565b156142495760405162461bcd60e51b81526004016108d190615b02565b836003806142698360009081526006602052604090206007015460ff1690565b600381111561428857634e487b7160e01b600052602160045260246000fd5b146142a55760405162461bcd60e51b81526004016108d190615b2c565b60008681526006602052604081209081818860018111156142d657634e487b7160e01b600052602160045260246000fd5b60018111156142f557634e487b7160e01b600052602160045260246000fd5b8152602001908152602001600020905061430f8888610991565b600185015460025460408051630afe914160e21b81529051939b506001600160a01b0392831696506101009091049091169350632bfa45049250600480820192602092909190829003018186803b15801561436957600080fd5b505afa15801561437d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143a1919061553b565b15614490576040516370a0823160e01b81526000906001600160a01b038316906370a08231906143d5903390600401615952565b60206040518083038186803b1580156143ed57600080fd5b505afa158015614401573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061442591906155f5565b9050801561448e57604051632770a7eb60e21b81526001600160a01b03831690639dc29fac9061445b9033908590600401615966565b600060405180830381600087803b15801561447557600080fd5b505af1158015614489573d6000803e3d6000fd5b505050505b505b600183015482546144af916001600160a01b0391821691168989614ca3565b6001828101546001600160a01b031660009081526004602090815260408083203384529091529020600201805461ff001916610100179055889081111561450657634e487b7160e01b600052602160045260246000fd5b6040518781528a9033907f84557df06a9cf3a49d0c3fb7e6ed5a54d316659c8d62d269901c3dfccf741fd89060200160405180910390a450505050509392505050565b604080516000808252602082019092526001600160a01b0384169083906040516145739190615936565b60006040518083038185875af1925050503d80600081146145b0576040519150601f19603f3d011682016040523d82523d6000602084013e6145b5565b606091505b50509050806145fc5760405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b60448201526064016108d1565b505050565b614609611b61565b156146265760405162461bcd60e51b81526004016108d190615b02565b61462f84614bd9565b600084815260066020526040812060018082015491926146bc9285926001600160a01b039091169187918691908a9081111561467b57634e487b7160e01b600052602160045260246000fd5b600181111561469a57634e487b7160e01b600052602160045260246000fd5b81526020810191909152604001600020546001600160a01b0316929190614ca3565b60008382828760018111156146e157634e487b7160e01b600052602160045260246000fd5b600181111561470057634e487b7160e01b600052602160045260246000fd5b815260200190815260200160002060040160008282546147209190615cb8565b9182905550915060009050600481848189600181111561475057634e487b7160e01b600052602160045260246000fd5b600181111561476f57634e487b7160e01b600052602160045260246000fd5b815260208082019290925260409081016000908120600101546001600160a01b031684528383019490945291820183203384529052812080549092506147b557856147fa565b8154869083906147c790600190615d03565b815481106147e557634e487b7160e01b600052603260045260246000fd5b90600052602060002001546147fa9190615cb8565b905061485984600089600181111561482257634e487b7160e01b600052602160045260246000fd5b600181111561484157634e487b7160e01b600052602160045260246000fd5b81526020019081526020016000206003015482614e9e565b600180830180548083018255600091825260208083209091018690558454808401865585835291200182905587908111156148a457634e487b7160e01b600052602160045260246000fd5b604051878152899033907f91ede45f04a37a7c170f5c1207df3b6bc748dc1e04ad5e917a241d0f52feada39060200160405180910390a45050505050505050565b6000828152600660205260409020600781015460ff16600283600381111561491d57634e487b7160e01b600052602160045260246000fd5b141561498b57600181600381111561494557634e487b7160e01b600052602160045260246000fd5b146149625760405162461bcd60e51b81526004016108d190615b2c565b42826009015411156149865760405162461bcd60e51b81526004016108d190615adc565b614a19565b60028160038111156149ad57634e487b7160e01b600052602160045260246000fd5b1480156149d9575060038360038111156149d757634e487b7160e01b600052602160045260246000fd5b145b6149f55760405162461bcd60e51b81526004016108d190615b2c565b4282600a01541115614a195760405162461bcd60e51b81526004016108d190615adc565b60078201805484919060ff19166001836003811115614a4857634e487b7160e01b600052602160045260246000fd5b021790555050505050565b60008080526020859052604090206004810154600290910154819015614ab557614ab282876000805b6001811115614a9b57634e487b7160e01b600052602160045260246000fd5b815260200190815260200160002060020154615052565b90505b600160009081526020879052604090206004810154600290910154819015614ae857614ae5828960006001614a7c565b90505b60018801546001600160a01b0316634c905348888584614b08828a615d03565b614b128789615d03565b6040516001600160e01b031960e088901b1681526004810195909552602485019390935260448401919091526064830152608482015260a4810189905260c4810188905260e4016040805180830381600087803b158015614b7257600080fd5b505af1158015614b86573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614baa91906156c4565b600080805260209a909a526040808b2060018c529a206005908101919091559098019790975550505050505050565b600081815260066020526040812090600782015460ff166003811115614c0f57634e487b7160e01b600052602160045260246000fd5b1415614c5d5760008160080154118015614c2d575042816008015411155b614c495760405162461bcd60e51b81526004016108d190615adc565b60078101805460ff1916600117905561421e565b6001600782015460ff166003811115614c8657634e487b7160e01b600052602160045260246000fd5b1461421e5760405162461bcd60e51b81526004016108d190615b2c565b6040516001600160a01b0380851660248301528316604482015260648101829052610eaf9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152615068565b614d16611b61565b15614d335760405162461bcd60e51b81526004016108d190615b02565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586140d83390565b6005546000906001600160a01b031615612a91576001600090815260208490526040812060035460068087015490830154929392614da69190615ce4565b614db09190615cd0565b90508082600701541115614e8057600354818360070154614dd19190615d03565b86600b0154614de09190615ce4565b614dea9190615cd0565b60018601546005548454929550614e11926001600160a01b03908116928116911686614ca3565b600554825460405163c56d414b60e01b8152600481018790526001600160a01b0391821660248201526044810186905291169063c56d414b90606401600060405180830381600087803b158015614e6757600080fd5b505af1158015614e7b573d6000803e3d6000fd5b505050505b505092915050565b6000612a91825490565b6000613e8a838361513a565b811580614eab5750818111155b61421e5760405162461bcd60e51b815260206004820152601060248201526f0457863656564732075736572206361760841b60448201526064016108d1565b6005810154600882015460009190808211613e8a5781610ce0565b8154600090614f1657506000612a91565b82546000905b80821015614f80576000614f3083836151ce565b905084868281548110614f5357634e487b7160e01b600052603260045260246000fd5b90600052602060002001541115614f6c57809150614f7a565b614f77816001615cb8565b92505b50614f1c565b600082118015614fc357508385614f98600185615d03565b81548110614fb657634e487b7160e01b600052603260045260246000fd5b9060005260206000200154145b15614fdc57614fd3600183615d03565b92505050612a91565b509050612a91565b6145fc8363a9059cbb60e01b8484604051602401614cd7929190615966565b600081815260018301602052604081205461504a57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155612a91565b506000612a91565b60008183106150615781613e8a565b5090919050565b60006150bd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166152259092919063ffffffff16565b8051909150156145fc57808060200190518101906150db919061553b565b6145fc5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016108d1565b815460009082106151985760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b60648201526084016108d1565b8260000182815481106151bb57634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b600060026151dc8184615d61565b6151e7600286615d61565b6151f19190615cb8565b6151fb9190615cd0565b615206600284615cd0565b615211600286615cd0565b61521b9190615cb8565b613e8a9190615cb8565b6060615234848460008561523c565b949350505050565b60608247101561529d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016108d1565b843b6152eb5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d1565b600080866001600160a01b031685876040516153079190615936565b60006040518083038185875af1925050503d8060008114615344576040519150601f19603f3d011682016040523d82523d6000602084013e615349565b606091505b5091509150615359828286615364565b979650505050505050565b60608315615373575081613e8a565b8251156153835782518084602001fd5b8160405162461bcd60e51b81526004016108d19190615a05565b604080516101608101825260008082526060602083018190529282018190529181018290526080810182905260a0810182905260c081018290529060e082019081526020016000815260200160008152602001600081525090565b803560028110610ce557600080fd5b600060208284031215615418578081fd5b8135613e8a81615dcd565b600080600060408486031215615437578182fd5b833567ffffffffffffffff8082111561544e578384fd5b818601915086601f830112615461578384fd5b81358181111561546f578485fd5b602088818360051b8601011115615484578586fd5b80840196508195508088013593508284111561549e578485fd5b838801935088601f8501126154b1578485fd5b83359150828211156154c5576154c5615db7565b8160051b604051601f19603f830116810181811086821117156154ea576154ea615db7565b604052838152828101945085830182870184018c1015615508578788fd5b8796505b8487101561552a57803586526001969096019594830194830161550c565b508096505050505050509250925092565b60006020828403121561554c578081fd5b81518015158114613e8a578182fd5b6000806040838503121561556d578182fd5b825161557881615dcd565b6020939093015192949293505050565b600060208284031215615599578081fd5b8151613e8a81615dcd565b6000602082840312156155b5578081fd5b813567ffffffffffffffff8111156155cb578182fd5b82016102008185031215613e8a578182fd5b6000602082840312156155ee578081fd5b5035919050565b600060208284031215615606578081fd5b5051919050565b600080600060608486031215615621578283fd5b83359250602084013561563381615dcd565b929592945050506040919091013590565b60008060408385031215615656578182fd5b82359150615666602084016153f8565b90509250929050565b600080600060608486031215615683578283fd5b83359250615693602085016153f8565b9150604084013590509250925092565b600080604083850312156156b5578182fd5b50508035926020909101359150565b600080604083850312156156d6578182fd5b505080516020909101519092909150565b6000806000606084860312156156fb578081fd5b8351925060208401519150604084015161571481615dcd565b809150509250925092565b600080600060608486031215615733578081fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561575f578182fd5b5050823594602084013594506040840135936060013592509050565b6000815180845260208085019450808401835b8381101561581857815180516001600160a01b03168852838101516157bd858a01826001600160a01b03169052565b5060408181015190890152606080820151908901526080808201519089015260a0808201519089015260c0808201519089015260e080820151908901526101009081015190880152610120909601959082019060010161578e565b509495945050505050565b6004811061583357615833615da1565b9052565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b60006101608251845260208301518160208601526158818286018261577b565b915050604083015161589e60408601826001600160a01b03169052565b5060608301516158b960608601826001600160a01b03169052565b5060808301516158d460808601826001600160a01b03169052565b5060a08301516158ef60a08601826001600160a01b03169052565b5060c083015160c085015260e083015161590c60e0860182615823565b50610100838101519085015261012080840151908501526101409283015192909301919091525090565b60008251615948818460208701615d1a565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6000602080830181845280855180835260408601915060408160051b8701019250838701855b828110156159d357603f198886030184526159c1858351615861565b945092850192908501906001016159a5565b5092979650505050505050565b9182526001600160a01b0316602082015260400190565b60208101612a918284615823565b6000602082528251806020840152615a24816040850160208701615d1a565b601f01601f19169190910160400192915050565b60208082526014908201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604082015260600190565b6020808252600e908201526d125b9d985b1a59081d185c99d95d60921b604082015260600190565b6020808252600c908201526b155b985d5d1a1bdc9a5e995960a21b604082015260600190565b6020808252600e908201526d24b73b30b634b21031b0b63632b960911b604082015260600190565b6020808252600c908201526b139bdd081d1a5b59481e595d60a21b604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b60208082526011908201527024b73b30b634b21037b832b930ba34b7b760791b604082015260600190565b6020808252601590820152745661756c7420746f6b656e7320696e61637469766560581b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208252613e8a6020830184615861565b8481526080810160028510615be757615be7615da1565b60208201949094526001600160a01b03929092166040830152606090910152919050565b600087825260806020830152615c25608083018789615837565b8281036040840152615c38818688615837565b91505060018060a01b0383166060830152979650505050505050565b92835260208301919091526001600160a01b0316604082015260600190565b6000808335601e19843603018112615c89578283fd5b83018035915067ffffffffffffffff821115615ca3578283fd5b602001915036819003821315613b1157600080fd5b60008219821115615ccb57615ccb615d75565b500190565b600082615cdf57615cdf615d8b565b500490565b6000816000190483118215151615615cfe57615cfe615d75565b500290565b600082821015615d1557615d15615d75565b500390565b60005b83811015615d35578181015183820152602001615d1d565b83811115610eaf5750506000910152565b6000600019821415615d5a57615d5a615d75565b5060010190565b600082615d7057615d70615d8b565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611a2457600080fdfea26469706673582212206f83520e73186e0d34ea28fcdd1adc14b68191e5363c32ce7275b80258e966a264736f6c63430008030033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000047d1f3fda174270244a1d800c49f3af456f0500400000000000000000000000051f07e597a2a7de7601767407a45fb3f581f7b7d
-----Decoded View---------------
Arg [0] : _registry (address): 0x47d1F3FDa174270244a1d800C49f3AF456f05004
Arg [1] : _trancheTokenImpl (address): 0x51F07e597A2A7De7601767407A45FB3f581F7b7D
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000047d1f3fda174270244a1d800c49f3af456f05004
Arg [1] : 00000000000000000000000051f07e597a2a7de7601767407a45fb3f581f7b7d
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.