Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 332 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 20217270 | 18 hrs ago | IN | 0 ETH | 0.00032747 | ||||
Withdraw | 20167380 | 7 days ago | IN | 0 ETH | 0.00060222 | ||||
Withdraw | 20111526 | 15 days ago | IN | 0 ETH | 0.00049013 | ||||
Claim Withdrawed... | 20095860 | 17 days ago | IN | 0 ETH | 0.00031831 | ||||
Claim Withdrawed... | 20083830 | 19 days ago | IN | 0 ETH | 0.00148842 | ||||
Claim Withdrawed... | 20083003 | 19 days ago | IN | 0 ETH | 0.00110866 | ||||
Process Deposits | 20082587 | 19 days ago | IN | 0 ETH | 0.00138717 | ||||
Process Deposits | 20082565 | 19 days ago | IN | 0 ETH | 0.00096492 | ||||
Rebalancing | 20082561 | 19 days ago | IN | 0 ETH | 0.00277292 | ||||
Rebalancing | 20082560 | 19 days ago | IN | 0 ETH | 0.00320642 | ||||
Withdraw | 20061239 | 22 days ago | IN | 0 ETH | 0.0004834 | ||||
Withdraw | 20016964 | 28 days ago | IN | 0 ETH | 0.0005252 | ||||
Withdraw | 19969004 | 35 days ago | IN | 0 ETH | 0.00210708 | ||||
Withdraw | 19945917 | 38 days ago | IN | 0 ETH | 0.00058709 | ||||
Claim Withdrawed... | 19890069 | 46 days ago | IN | 0 ETH | 0.00047552 | ||||
Claim Withdrawed... | 19882957 | 47 days ago | IN | 0 ETH | 0.0005036 | ||||
Claim Withdrawed... | 19882934 | 47 days ago | IN | 0 ETH | 0.00053904 | ||||
Claim Withdrawed... | 19882926 | 47 days ago | IN | 0 ETH | 0.00060589 | ||||
Process Deposits | 19882549 | 47 days ago | IN | 0 ETH | 0.00043794 | ||||
Rebalancing | 19882543 | 47 days ago | IN | 0 ETH | 0.00139544 | ||||
Process Deposits | 19882538 | 47 days ago | IN | 0 ETH | 0.00048694 | ||||
Rebalancing | 19882534 | 47 days ago | IN | 0 ETH | 0.00144919 | ||||
Withdraw | 19877725 | 48 days ago | IN | 0 ETH | 0.00105099 | ||||
Withdraw | 19863527 | 50 days ago | IN | 0 ETH | 0.00110015 | ||||
Withdraw | 19863518 | 50 days ago | IN | 0 ETH | 0.00103432 |
Latest 2 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
18162563 | 288 days ago | Contract Creation | 0 ETH | |||
18162563 | 288 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
CIVVault
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /** * @title Civ Vault * @author Ren / Frank */ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./dependencies/FixedPoint.sol"; import "./interfaces/ICivFund.sol"; import "./CIV-VaultGetter.sol"; import "./CIV-VaultFactory.sol"; contract CIVVault is Ownable, ReentrancyGuard { using SafeERC20 for IERC20; using SafeERC20 for ICivFundRT; using FixedPoint for *; /// @notice All Fees Base Amount uint public constant feeBase = 10_000; /// @notice Safety Factor to avoid out of Gas in loops uint public gasBuffer; /// @notice Number of strategies uint public strategiesCounter; /// @notice vault getter contract ICivVaultGetter public vaultGetter; /// @notice share factory contract CIVFundShareFactory public fundShareFactory; /// @notice mapping with info on each strategy mapping(uint => StrategyInfo) private _strategyInfo; /// @notice structure with epoch info mapping(uint => mapping(uint => EpochInfo)) private _epochInfo; /// @notice Info of each user that enters the fund mapping(uint => mapping(address => UserInfo)) private _userInfo; /// @notice Counter for the epochs of each strategy mapping(uint => uint) private _epochCounter; /// @notice Each Strategies epoch informations per address mapping(uint => mapping(address => mapping(uint => UserInfoEpoch))) private _userInfoEpoch; /// @notice Mapping of depositors on a particular epoch mapping(uint => mapping(uint => mapping(uint => address))) private _depositors; /// @notice Mapping of guarantee locks on a strategy for each user mapping(uint => mapping(address => mapping(uint => GuaranteeInfo))) private _userGuaranteeLock; // Index of the depositor in the depositors mapping ////////////////// EVENTS ////////////////// /// @notice Event emitted when user deposit fund to our vault or vault deposit fund to strategy event Deposit( address indexed user, address receiver, uint indexed id, uint amount ); /// @notice Event emitted when user request withdraw fund from our vault or vault withdraw fund to user event Withdraw(address indexed user, uint indexed id, uint amount); /// @notice Event emitted when owner sets new fee event SetFee( uint id, uint oldFee, uint newFee, uint oldDuration, uint newDuration ); /// @notice Event emitted when owner sets new guarantee fee event SetGuaranteeFee(uint oldFee, uint newFee); /// @notice Event emitted when owner sets new gas buffer event SetGasBuffer(uint gasBuffer, uint newGasBuffer); /// @notice Event emitted when owner sets new deposit duration event SetEpochDuration(uint id, uint oldDuration, uint newDuration); /// @notice Event emitted when owner sets new guarantee token lock time event SetGuaranteeLockTime(uint id, uint oldLocktime, uint newLockTime); /// @notice Event emitted when owner sets new treasury addresses event SetWithdrawAddress( uint id, address[] oldAddress, address[] newAddress ); /// @notice Event emitted when owner sets new invest address event SetInvestAddress(uint id, address oldAddress, address newAddress); /// @notice Event emitted when send fee to our treasury event SendFeeWithOwner(uint id, address treasuryAddress, uint feeAmount); /// @notice Event emitted when owner update new VPS event UpdateVPS(uint id, uint lastEpoch, uint VPS); /// @notice Event emitted when owner paused deposit event SetPaused(uint id, bool paused); /// @notice Event emitted when owner set new Max & Min Deposit Amount event SetLimits( uint id, uint oldMaxAmount, uint newMaxAmount, uint oldMinAmount, uint newMinAmount, uint oldMaxUsers, uint newMaxUsers ); /// @notice Event emitted when user cancel pending deposit from vault event CancelDeposit(address user, uint id, uint amount); /// @notice Event emitted when user cancel withdraw request from vault event CancelWithdraw(address user, uint id, uint amount); /// @notice Event emitted when Uniswap Token Price Updated event Update(uint id, uint index); /// @notice Event emitted when user claim guarantee token event ClaimGuarantee(uint id, address user, uint guaranteeAmount); /// @notice Event emitted when user claim Asset token for each epoch event ClaimWithdrawedToken( uint id, address user, uint epoch, uint assetAmount ); /// @notice Event emitted when user claim Asset token event WithdrawedToken(uint id, address user, uint assetAmount); /// @notice Event emitted when owner adds new strategy event AddStrategy( uint indexed id, uint indexed fee, uint maxDeposit, uint minDeposit, bool paused, address[] withdrawAddress, address assetToken, address guaranteeToken, uint lockPeriod, uint feeDuration ); /// @notice Event emitted when strategy is initialized event InitializeStrategy(uint indexed id); ////////////////// ERROR CODES ////////////////// /* ERR_V.1 = "Strategy does not exist"; ERR_V.2 = "Deposit paused"; ERR_V.3 = "Treasury Address Length must be 2"; ERR_V.4 = "Burn failed"; ERR_V.5 = "Guarantee Token address cannot be null address"; ERR_V.6 = "First Treasury address cannot be null address"; ERR_V.7 = "Second Treasury address cannot be null address"; ERR_V.8 = "Minting failed"; ERR_V.9 = "Strategy already initialized"; ERR_V.10 = "No epochs exist"; ERR_V.11 = "Wait for the previos epoch to settle before requesting withdraw"; ERR_V.12 = "Insufficient contract balance"; ERR_V.13 = "Not enough amount to withdraw"; ERR_V.14 = "Strategy address cannot be null address"; ERR_V.15 = "Enable withdraw for previous epoch"; ERR_V.16 = "Distribute all shares for previous epoch"; ERR_V.17 = "Epoch does not exist"; ERR_V.18 = "Epoch not yet expired"; ERR_V.19 = "No funds available to withdraw"; ERR_V.20 = "Amount can't be 0"; ERR_V.21 = "Insufficient User balance"; ERR_V.22 = "No more users are allowed"; ERR_V.23 = "Deposit amount exceeds epoch limit"; ERR_V.24 = "Epoch expired"; ERR_V.25 = "Current balance not enough"; ERR_V.26 = "Not enough total withdrawals"; ERR_V.27 = "VPS not yet updated"; ERR_V.28 = "Already started distribution"; ERR_V.29 = "Not yet distributed"; ERR_V.30 = "Already distributed"; ERR_V.31 = "Fee duration not yet passed"; ERR_V.32 = "Vault balance is not enough to pay fees"; ERR_V.33 = "Transfer Failed"; ERR_V.34 = "Withdraw Token cannot be deposit token"; ERR_V.35 = "No pending Fees to distribute"; ERR_V.36 = "Nothing to claim"; ERR_V.37 = "Wait for rebalancing to complete"; */ ////////////////// MODIFIER ////////////////// modifier checkStrategyExistence(uint _id) { require(strategiesCounter > _id, "ERR_V.1"); _; } modifier checkEpochExistence(uint _id) { require(_epochCounter[_id] > 0, "ERR_V.10"); _; } ////////////////// CONSTRUCTOR ////////////////// constructor() { CivVaultGetter getterContract = new CivVaultGetter(address(this)); fundShareFactory = new CIVFundShareFactory(); vaultGetter = ICivVaultGetter(address(getterContract)); } ////////////////// INITIALIZATION ////////////////// /// @notice Add new strategy to our vault /// @dev Only Owner can call this function /// @param addStrategyParam Parameters for new strategy function addStrategy( AddStrategyParam memory addStrategyParam ) external virtual nonReentrant onlyOwner { require(addStrategyParam._withdrawAddresses.length == 2, "ERR_V.3"); require( address(addStrategyParam._guaranteeToken) != address(0), "ERR_V.5" ); require( addStrategyParam._withdrawAddresses[0] != address(0), "ERR_V.6" ); require( addStrategyParam._withdrawAddresses[1] != address(0), "ERR_V.7" ); /// deploy new CIVFundShare contract CIVFundShare fundRepresentToken = fundShareFactory.createCIVFundShare(); _strategyInfo[strategiesCounter] = StrategyInfo({ assetToken: addStrategyParam._assetToken, fundRepresentToken: ICivFundRT(address(fundRepresentToken)), guaranteeToken: addStrategyParam._guaranteeToken, fee: addStrategyParam._fee, guaranteeFee: addStrategyParam._guaranteeFee, withdrawAddress: addStrategyParam._withdrawAddresses, investAddress: addStrategyParam._investAddress, initialized: false, pendingFees: 0, maxDeposit: addStrategyParam._maxDeposit, maxUsers: addStrategyParam._maxUsers, minDeposit: addStrategyParam._minAmount, paused: addStrategyParam._paused, epochDuration: addStrategyParam._epochDuration, lockPeriod: addStrategyParam._lockPeriod, feeDuration: addStrategyParam._feeDuration, lastFeeDistribution: 0, lastProcessedEpoch: 0, watermark: 0 }); uint id = strategiesCounter; strategiesCounter++; vaultGetter.addUniPair( id, address(addStrategyParam._assetToken), address(addStrategyParam._guaranteeToken) ); emit AddStrategy( id, addStrategyParam._fee, addStrategyParam._maxDeposit, addStrategyParam._minAmount, addStrategyParam._paused, addStrategyParam._withdrawAddresses, address(addStrategyParam._assetToken), address(addStrategyParam._guaranteeToken), addStrategyParam._lockPeriod, addStrategyParam._feeDuration ); } /// @notice Delayed strategy start /// @dev Only Owner can call this function /// @param _id strategy id function initializeStrategy( uint _id ) external onlyOwner checkStrategyExistence(_id) { require(!_strategyInfo[_id].initialized, "ERR_V.9"); _strategyInfo[_id].initialized = true; vaultGetter.addTimeOracle(_id, _strategyInfo[_id].epochDuration); _epochInfo[_id][_epochCounter[_id]] = EpochInfo({ totDepositors: 0, totDepositedAssets: 0, totWithdrawnShares: 0, VPS: 0, newShares: 0, currentWithdrawAssets: 0, epochStartTime: block.timestamp, lastDepositorProcessed: 0, duration: _strategyInfo[_id].epochDuration }); _epochCounter[_id]++; emit InitializeStrategy(_id); } ////////////////// SETTER ////////////////// /// @notice Sets new fee and new collecting fee duration /// @dev Only Owner can call this function /// @param _id Strategy Id /// @param _newFee New Fee Percent /// @param _newDuration New Collecting Fee Duration function setFee( uint _id, uint _newFee, uint _newDuration ) external onlyOwner checkStrategyExistence(_id) { emit SetFee( _id, _strategyInfo[_id].fee, _newFee, _strategyInfo[_id].feeDuration, _newDuration ); _strategyInfo[_id].fee = _newFee; _strategyInfo[_id].feeDuration = _newDuration; } /// @notice Sets new Strategy guarantee token lock time and guarantee fee /// @dev Only Owner can call this function /// @param _id Strategy Id /// @param _lockTime New Guarantee token lock time /// @param _newFee new guarantee fee amount function setStrategyGuarantee( uint _id, uint _lockTime, uint _newFee ) external onlyOwner checkStrategyExistence(_id) { emit SetGuaranteeLockTime( _id, _strategyInfo[_id].lockPeriod, _lockTime ); emit SetGuaranteeFee(_strategyInfo[_id].guaranteeFee, _newFee); _strategyInfo[_id].lockPeriod = _lockTime; _strategyInfo[_id].guaranteeFee = _newFee; } /// @notice Sets new deposit fund from vault to strategy duration /// @dev Only Owner can call this function /// @param _id Strategy Id /// @param _newDuration New Duration for Deposit fund from vault to strategy function setEpochDuration( uint _id, uint _newDuration ) external onlyOwner checkStrategyExistence(_id) { emit SetEpochDuration( _id, _strategyInfo[_id].epochDuration, _newDuration ); vaultGetter.setEpochDuration(_id, _newDuration); _strategyInfo[_id].epochDuration = _newDuration; } /// @notice Sets new treasury addresses to keep fee /// @dev Only Owner can call this function /// @param _id Strategy Id /// @param _newAddress Address list to keep fee function setWithdrawAddress( uint _id, address[] memory _newAddress ) external onlyOwner checkStrategyExistence(_id) { require(_newAddress.length == 2, "ERR_V.3"); require(_newAddress[0] != address(0), "ERR_V.6"); require(_newAddress[1] != address(0), "ERR_V.7"); emit SetWithdrawAddress( _id, _strategyInfo[_id].withdrawAddress, _newAddress ); _strategyInfo[_id].withdrawAddress = _newAddress; } /// @notice Sets new treasury addresses to keep fee /// @dev Only Owner can call this function /// @param _id Strategy Id /// @param _newAddress Address list to keep fee function setInvestAddress( uint _id, address _newAddress ) external onlyOwner checkStrategyExistence(_id) { require(_newAddress != address(0), "ERR_V.14"); emit SetInvestAddress( _id, _strategyInfo[_id].investAddress, _newAddress ); _strategyInfo[_id].investAddress = _newAddress; } /// @notice Set Pause of Unpause for deposit to vault /// @dev Only Owner can change this status /// @param _id Strategy Id /// @param _paused paused or unpaused for deposit function setPaused( uint _id, bool _paused ) external onlyOwner checkStrategyExistence(_id) { emit SetPaused(_id, _paused); _strategyInfo[_id].paused = _paused; } /// @notice Set limits on a given strategy /// @dev Only Owner can change this status /// @param _id Strategy Id /// @param _newMaxDeposit New Max Deposit Amount /// @param _newMinDeposit New Min Deposit Amount /// @param _newMaxUsers New Max User Count function setEpochLimits( uint _id, uint _newMaxDeposit, uint _newMinDeposit, uint _newMaxUsers ) external onlyOwner checkStrategyExistence(_id) { emit SetLimits( _id, _strategyInfo[_id].maxDeposit, _newMaxDeposit, _strategyInfo[_id].minDeposit, _newMinDeposit, _strategyInfo[_id].maxUsers, _newMaxUsers ); _strategyInfo[_id].maxDeposit = _newMaxDeposit; _strategyInfo[_id].minDeposit = _newMinDeposit; _strategyInfo[_id].maxUsers = _newMaxUsers; } /// @notice Sets new gas buffer /// @dev Only Owner can call this function /// @param _gasBuffer new gas buffer amount function setGasBuffer(uint _gasBuffer) external onlyOwner { emit SetGasBuffer(gasBuffer, _gasBuffer); gasBuffer = _gasBuffer; } ////////////////// GETTER ////////////////// /** * @dev Fetches the strategy information for a given strategy _id. * @param _id The ID of the strategy to fetch the information for. * @return strategy The StrategyInfo struct associated with the provided _id. */ function getStrategyInfo( uint _id ) external view checkStrategyExistence(_id) returns (StrategyInfo memory strategy) { strategy = _strategyInfo[_id]; } /** * @dev Fetches the epoch information for a given strategy _id. * @param _id The ID of the strategy to fetch the information for. * @param _index The index of the epoch to fetch the information for. * @return epoch The EpochInfo struct associated with the provided _id and _index. */ function getEpochInfo( uint _id, uint _index ) external view checkStrategyExistence(_id) checkEpochExistence(_id) returns (EpochInfo memory epoch) { epoch = _epochInfo[_id][_index]; } /** * @dev Fetches the current epoch number for a given strategy _id. * The current epoch is determined as the last index of the epochInfo mapping for the strategy. * @param _id The _id of the strategy to fetch the current epoch for. * @return The current epoch number for the given strategy _id. */ function getCurrentEpoch( uint _id ) public view checkStrategyExistence(_id) checkEpochExistence(_id) returns (uint) { return _epochCounter[_id] - 1; } /** * @dev Fetches the user information for a given strategy _id. * @param _id The _id of the strategy to fetch the information for. * @param _user The address of the user to fetch the information for. * @return user The UserInfo struct associated with the provided _id and _user. */ function getUserInfo( uint _id, address _user ) external view checkStrategyExistence(_id) returns (UserInfo memory user) { user = _userInfo[_id][_user]; } /** * @dev Fetches the user information for a given strategy _id. * @param _id The _id of the strategy to fetch the information for. * @param _epoch The starting index to fetch the information for. * @return users An array of addresses of unique depositors. */ function getDepositors( uint _id, uint _epoch ) external view checkStrategyExistence(_id) returns (address[] memory users) { // Initialize the return array with the size equal to the range between the start and end indices users = new address[](_epochInfo[_id][_epoch].totDepositors); // Loop through the mapping to populate the return array for (uint i = 0; i < _epochInfo[_id][_epoch].totDepositors; i++) { users[i] = _depositors[_id][_epoch][i]; } } /** * @dev Fetches the deposit parameters for a given strategy _id. * @param _id The _id of the strategy to fetch the information for. * @param _user The address of the user to fetch the information for. * @param _index The index of the deposit to fetch the information for. * @return userEpochStruct The UserInfoEpoch struct associated with the provided _id, _user and _index. */ function getUserInfoEpoch( uint _id, address _user, uint _index ) external view checkStrategyExistence(_id) returns (UserInfoEpoch memory userEpochStruct) { userEpochStruct = _userInfoEpoch[_id][_user][_index]; } /** * @dev Fetches the guarantee parameters for an user for a certain index. * @param _id The _id of the strategy to fetch the information for. * @param _user The address of the user to fetch the information for. * @param _index The index of the user guarantee lock to fetch the information for. * @return userGuarantee The UserInfoEpoch struct associated with the provided id, _user and _index. */ function getGuaranteeInfo( uint _id, address _user, uint _index ) external view checkStrategyExistence(_id) returns (GuaranteeInfo memory userGuarantee) { userGuarantee = _userGuaranteeLock[_id][_user][_index]; } ////////////////// UPDATE ////////////////// /** * @dev Updates the current epoch information for the specified strategy * @param _id The Strategy _id * * This function checks if the current epoch's duration has been met or exceeded. * If true, it initializes a new epoch with its starting time as the current block timestamp. * If false, no action is taken. * * Requirements: * - The strategy must be initialized. * - The current block timestamp must be equal to or greater than the start * time of the current epoch plus the epoch's duration. */ function updateEpoch( uint _id ) private checkEpochExistence(_id) { uint currentEpoch = getCurrentEpoch(_id); if ( block.timestamp >= _epochInfo[_id][currentEpoch].epochStartTime + _epochInfo[_id][currentEpoch].duration ) { require(_epochInfo[_id][currentEpoch].VPS > 0, "ERR_V.37"); _epochInfo[_id][_epochCounter[_id]] = EpochInfo({ totDepositors: 0, totDepositedAssets: 0, totWithdrawnShares: 0, VPS: 0, newShares: 0, currentWithdrawAssets: 0, epochStartTime: vaultGetter.getCurrentPeriod(_id), lastDepositorProcessed: 0, duration: _strategyInfo[_id].epochDuration }); _epochCounter[_id]++; } } /// @notice Calculate fees to the treasury address and save it in the strategy mapping and returns adjusted VPS /** * @dev Internal function */ /// @param _id Strategy _id /// @param _newVPS new Net Asset Value /// @return adjustedVPS The new VPS after fees have been deducted function takePerformanceFees( uint _id, uint _newVPS ) private returns (uint adjustedVPS, uint actualFee) { StrategyInfo storage strategy = _strategyInfo[_id]; uint sharesMultiplier = 10 ** strategy.fundRepresentToken.decimals(); uint totalSupplyShares = strategy.fundRepresentToken.totalSupply(); actualFee = 0; adjustedVPS = _newVPS; if (strategy.watermark < _newVPS) { actualFee = ((_newVPS - strategy.watermark) * strategy.fee * totalSupplyShares) / feeBase / sharesMultiplier; if (actualFee > 0) { strategy.watermark = _newVPS; strategy.pendingFees += actualFee; // Calculate adjusted VPS based on the actual fee uint adjustedTotalValue = (_newVPS * totalSupplyShares) / sharesMultiplier - actualFee; adjustedVPS = (adjustedTotalValue * sharesMultiplier) / totalSupplyShares; } } } /** * @dev Processes the fund associated with a particular strategy, handling deposits, * minting, and burning of shares. * @param _id The Strategy _id * @param _newVPS New value per share (VPS) expressed in decimals (same as assetToken) * - must be greater than 0 * * This function performs the following actions: * 1. Retrieves the current epoch and strategy info, as well as adjusted VPS and performance Fees; * 2. Calculate the new shares and current withdrawal based on new VPS; * 3. Mints or burns shares depending on the new shares and total withdrawals. * 4. Handles deposits, withdrawals and performance fees by transferring the Asset tokens. * * Requirements: * - `_newVPS` must be greater than 0. * - The necessary amount of Asset tokens must be present in the contract for deposits if required. * - The necessary amount of Asset tokens must be present in the investAddress for withdrawals if required. */ function processFund(uint _id, uint _newVPS) private { require(_newVPS > 0, "ERR_V.35"); uint performanceFees; (_newVPS, performanceFees) = takePerformanceFees(_id, _newVPS); // Step 1 EpochInfo storage epoch = _epochInfo[_id][ _strategyInfo[_id].lastProcessedEpoch ]; StrategyInfo memory strategy = _strategyInfo[_id]; uint sharesMultiplier = 10 ** strategy.fundRepresentToken.decimals(); // Step 2 uint newShares = (epoch.totDepositedAssets * sharesMultiplier) / _newVPS; uint currentWithdrawAssets = (_newVPS * epoch.totWithdrawnShares) / sharesMultiplier; epoch.newShares = newShares; epoch.currentWithdrawAssets = currentWithdrawAssets; // Step 3 if (newShares > epoch.totWithdrawnShares) { uint sharesToMint = newShares - epoch.totWithdrawnShares; bool success = strategy.fundRepresentToken.mint(sharesToMint); require(success, "ERR_V.8"); } else { uint offSetShares = epoch.totWithdrawnShares - newShares; if (offSetShares > 0) { bool success = strategy.fundRepresentToken.burn(offSetShares); require(success, "ERR_V.4"); } } // Step 4 if (epoch.totDepositedAssets >= currentWithdrawAssets + performanceFees) { uint netDeposits = epoch.totDepositedAssets - currentWithdrawAssets - performanceFees; if (netDeposits > 0) { require( strategy.assetToken.balanceOf(address(this)) >= netDeposits, "ERR_V.12" ); strategy.assetToken.safeTransfer( strategy.investAddress, netDeposits ); emit Deposit( address(this), strategy.investAddress, _id, netDeposits ); } } else { uint offSet = currentWithdrawAssets + performanceFees - epoch.totDepositedAssets; require( strategy.assetToken.balanceOf(strategy.investAddress) >= offSet, "ERR_V.13" ); strategy.assetToken.safeTransferFrom( strategy.investAddress, address(this), offSet ); } updateEpoch(_id); } /// @notice Sets new VPS of the strategy. /** * @dev Only Owner can call this function. * Owner must transfer fund to our vault before calling this function */ /// @param _id Strategy _id /// @param _newVPS New VPS value function rebalancing( uint _id, uint _newVPS ) external nonReentrant onlyOwner checkStrategyExistence(_id) { StrategyInfo storage strategy = _strategyInfo[_id]; require(strategy.investAddress != address(0), "ERR_V.14"); if (strategy.lastProcessedEpoch == 0) { EpochInfo storage initEpoch = _epochInfo[_id][0]; if (initEpoch.VPS > 0) { require( initEpoch.lastDepositorProcessed == initEpoch.totDepositors, "ERR_V.16" ); require(_epochCounter[_id] > 1, "ERR_V.17"); strategy.lastProcessedEpoch++; EpochInfo storage newEpoch = _epochInfo[_id][1]; require( block.timestamp >= newEpoch.epochStartTime + newEpoch.duration, "ERR_V.18" ); newEpoch.VPS = _newVPS; } else { require( block.timestamp >= initEpoch.epochStartTime + initEpoch.duration, "ERR_V.18" ); strategy.watermark = _newVPS; initEpoch.VPS = _newVPS; } } else { require( _epochInfo[_id][strategy.lastProcessedEpoch] .lastDepositorProcessed == _epochInfo[_id][strategy.lastProcessedEpoch].totDepositors, "ERR_V.16" ); strategy.lastProcessedEpoch++; require( _epochCounter[_id] > strategy.lastProcessedEpoch, "ERR_V.17" ); EpochInfo storage subsequentEpoch = _epochInfo[_id][ strategy.lastProcessedEpoch ]; require( block.timestamp >= subsequentEpoch.epochStartTime + subsequentEpoch.duration, "ERR_V.18" ); subsequentEpoch.VPS = _newVPS; } processFund(_id, _newVPS); emit UpdateVPS(_id, strategy.lastProcessedEpoch, _newVPS); } ////////////////// MAIN ////////////////// /// @notice Claim withdrawed token epochs /// @param _id Strategy _id function claimGuaranteeToken( uint _id ) external nonReentrant checkStrategyExistence(_id) checkEpochExistence(_id) { StrategyInfo memory strategy = _strategyInfo[_id]; UserInfo storage user = _userInfo[_id][_msgSender()]; uint endIndex = user.numberOfLocks; uint startingIndexFinal = user.startingIndexGuarantee; uint actualGuarantee; for (uint i = user.startingIndexGuarantee; i < endIndex; i++) { if ( block.timestamp < _userGuaranteeLock[_id][_msgSender()][i].lockStartTime + strategy.lockPeriod ) { break; } actualGuarantee += _userGuaranteeLock[_id][_msgSender()][i] .lockAmount; startingIndexFinal = i + 1; } require(actualGuarantee > 0, "ERR_V.19"); user.startingIndexGuarantee = startingIndexFinal; strategy.guaranteeToken.safeTransfer(_msgSender(), actualGuarantee); emit ClaimGuarantee(_id, _msgSender(), actualGuarantee); } /// @notice Users Deposit tokens to our vault /** * @dev Anyone can call this function if strategy is not paused. * Users must approve deposit token before calling this function * We mint represent token to users so that we can calculate each users deposit amount outside */ /// @param _id Strategy _id /// @param _amount Token Amount to deposit function deposit( uint _id, uint _amount ) external nonReentrant checkStrategyExistence(_id) { require(_strategyInfo[_id].paused == false, "ERR_V.2"); StrategyInfo storage strategy = _strategyInfo[_id]; require(_amount > strategy.minDeposit, "ERR_V.20"); require( strategy.assetToken.balanceOf(_msgSender()) >= _amount, "ERR_V.21" ); uint curEpoch = getCurrentEpoch(_id); EpochInfo storage epoch = _epochInfo[_id][curEpoch]; require (block.timestamp <= epoch.epochStartTime + epoch.duration, "ERR_V.37" ); UserInfoEpoch storage userEpoch = _userInfoEpoch[_id][_msgSender()][ curEpoch ]; UserInfo storage user = _userInfo[_id][_msgSender()]; require( epoch.totDepositedAssets + _amount <= strategy.maxDeposit, "ERR_V.23" ); // Transfer guarantee token to the vault. vaultGetter.updateAll(_id); uint guaranteeAmount = (vaultGetter.getPrice(_id, _amount) * strategy.guaranteeFee) / feeBase; strategy.guaranteeToken.safeTransferFrom( _msgSender(), address(this), guaranteeAmount ); GuaranteeInfo storage guaranteeInfo = _userGuaranteeLock[_id][ _msgSender() ][user.numberOfLocks]; if (userEpoch.epochGuaranteeIndex == 0) userEpoch.epochGuaranteeIndex = user.numberOfLocks; user.numberOfLocks++; guaranteeInfo.lockStartTime = block.timestamp; guaranteeInfo.lockAmount = guaranteeAmount; if (!userEpoch.hasDeposited) { require(epoch.totDepositors + 1 <= strategy.maxUsers, "ERR_V.22"); _depositors[_id][curEpoch][epoch.totDepositors] = _msgSender(); userEpoch.depositIndex = epoch.totDepositors; epoch.totDepositors++; userEpoch.hasDeposited = true; } epoch.totDepositedAssets += _amount; strategy.assetToken.safeTransferFrom( _msgSender(), address(this), _amount ); userEpoch.depositInfo += _amount; emit Deposit(_msgSender(), address(this), _id, _amount); } /// @notice Immediately withdraw current pending deposit amount /// @param _id Strategy _id function cancelDeposit( uint _id ) external nonReentrant checkStrategyExistence(_id) checkEpochExistence(_id) { StrategyInfo storage strategy = _strategyInfo[_id]; uint curEpoch = getCurrentEpoch(_id); EpochInfo storage epoch = _epochInfo[_id][curEpoch]; require( block.timestamp < epoch.epochStartTime + epoch.duration, "ERR_V.24" ); UserInfoEpoch storage userEpoch = _userInfoEpoch[_id][_msgSender()][ curEpoch ]; uint amount = userEpoch.depositInfo; require(amount > 0, "ERR_V.20"); userEpoch.depositInfo = 0; epoch.totDepositedAssets -= amount; strategy.assetToken.safeTransfer(_msgSender(), amount); UserInfo storage user = _userInfo[_id][_msgSender()]; // Guarantee refund logic start // uint actualGuarantee; uint iterations; for ( uint i = userEpoch.epochGuaranteeIndex; i < user.numberOfLocks; i++ ) { actualGuarantee += _userGuaranteeLock[_id][_msgSender()][i] .lockAmount; iterations++; } user.numberOfLocks -= iterations; strategy.guaranteeToken.safeTransfer(_msgSender(), actualGuarantee); // Guarantee refund logic end // if (_depositors[_id][curEpoch][epoch.totDepositors] == _depositors[_id][curEpoch][userEpoch.depositIndex]) { _depositors[_id][curEpoch][epoch.totDepositors] = address(0); } else { address replaceAddress = _depositors[_id][curEpoch][epoch.totDepositors]; _depositors[_id][curEpoch][epoch.totDepositors] = address(0); _depositors[_id][curEpoch][userEpoch.depositIndex] = replaceAddress; _userInfoEpoch[_id][replaceAddress][curEpoch].depositIndex = userEpoch .depositIndex; } userEpoch.depositIndex = 0; epoch.totDepositors--; userEpoch.hasDeposited = false; emit CancelDeposit(_msgSender(), _id, amount); } /// @notice Sends Withdraw Request to vault /** * @dev Withdraw amount user shares from vault */ /// @param _id Strategy _id function withdraw( uint _id, uint _amount ) external nonReentrant checkStrategyExistence(_id) checkEpochExistence(_id) { uint sharesBalance = _strategyInfo[_id].fundRepresentToken.balanceOf( _msgSender() ); require(sharesBalance >= _amount, "ERR_V.25"); uint curEpoch = getCurrentEpoch(_id); require (block.timestamp <= _epochInfo[_id][curEpoch].epochStartTime + _epochInfo[_id][curEpoch].duration, "ERR_V.37" ); UserInfoEpoch storage userEpoch = _userInfoEpoch[_id][_msgSender()][ curEpoch ]; UserInfo storage user = _userInfo[_id][_msgSender()]; if (user.lastEpoch > 0 && userEpoch.withdrawInfo == 0) _claimWithdrawedTokens(_id, user.lastEpoch, _msgSender()); _epochInfo[_id][curEpoch].totWithdrawnShares += _amount; userEpoch.withdrawInfo += _amount; if (user.lastEpoch != curEpoch) user.lastEpoch = curEpoch; _strategyInfo[_id].fundRepresentToken.safeTransferFrom( _msgSender(), address(this), _amount ); emit Withdraw(_msgSender(), _id, _amount); } /// @notice Immediately withdraw current pending shares amount /// @param _id Strategy _id function cancelWithdraw( uint _id ) external nonReentrant checkStrategyExistence(_id) checkEpochExistence(_id) { StrategyInfo storage strategy = _strategyInfo[_id]; uint curEpoch = getCurrentEpoch(_id); EpochInfo storage epoch = _epochInfo[_id][curEpoch]; require( block.timestamp < epoch.epochStartTime + epoch.duration, "ERR_V.24" ); UserInfoEpoch storage userEpoch = _userInfoEpoch[_id][_msgSender()][ curEpoch ]; UserInfo storage user = _userInfo[_id][_msgSender()]; uint amount = userEpoch.withdrawInfo; require(amount > 0, "ERR_V.20"); userEpoch.withdrawInfo = 0; user.lastEpoch = 0; require(epoch.totWithdrawnShares >= amount, "ERR_V.26"); epoch.totWithdrawnShares -= amount; strategy.fundRepresentToken.safeTransfer(_msgSender(), amount); emit CancelWithdraw(_msgSender(), _id, amount); } /// @notice Internal get withdraw tokens from vault for user /** * @dev Withdraw user funds from vault */ /// @param _id Strategy _id /// @param _user Strategy _id function _claimWithdrawedTokens( uint _id, uint _lastEpoch, address _user ) internal { EpochInfo storage epoch = _epochInfo[_id][_lastEpoch]; uint withdrawInfo = _userInfoEpoch[_id][_user][_lastEpoch].withdrawInfo; uint availableToClaim; if (withdrawInfo > 0) { uint dueWithdraw = (withdrawInfo * epoch.currentWithdrawAssets) / epoch.totWithdrawnShares; availableToClaim += dueWithdraw; emit ClaimWithdrawedToken(_id, _user, _lastEpoch, dueWithdraw); } if (availableToClaim > 0) _strategyInfo[_id].assetToken.safeTransfer(_user, availableToClaim); emit WithdrawedToken(_id, _user, availableToClaim); } /// @notice Get withdraw tokens from vault /** * @dev Withdraw my fund from vault */ /// @param _id Strategy _id function claimWithdrawedTokens( uint _id ) external nonReentrant checkStrategyExistence(_id) { UserInfo storage user = _userInfo[_id][_msgSender()]; uint lastEpoch = user.lastEpoch; require(lastEpoch > 0, "ERR_V.36"); _claimWithdrawedTokens(_id, lastEpoch, _msgSender()); user.lastEpoch = 0; } /// @notice Distribute shares to the epoch depositors /** * @dev Only Owner can call this function if deposit duration is passed. * Owner must setPaused(false) */ /// @param _id Strategy _id function processDeposits( uint _id ) external nonReentrant onlyOwner checkStrategyExistence(_id) { StrategyInfo memory strategy = _strategyInfo[_id]; EpochInfo memory epoch = _epochInfo[_id][strategy.lastProcessedEpoch]; require(epoch.VPS > 0, "ERR_V.27"); require(epoch.lastDepositorProcessed == 0, "ERR_V.28"); if (epoch.totDepositedAssets == 0) { return; } distributeShares(_id); } /** * @dev Continues the process of distributing shares for a specific strategy, if possible. * This function is only callable by the contract owner. * @param _id The _id of the strategy for which to continue distributing shares. */ function continueDistributingShares( uint _id ) external nonReentrant onlyOwner checkStrategyExistence(_id) { // Check if there's anything to distribute EpochInfo memory epoch = _epochInfo[_id][ _strategyInfo[_id].lastProcessedEpoch ]; require(epoch.VPS > 0, "ERR_V.27"); require(epoch.lastDepositorProcessed != 0, "ERR_V.29"); require(epoch.lastDepositorProcessed < epoch.totDepositors, "ERR_V.30"); distributeShares(_id); } /** * @dev Distributes the newly minted shares among the depositors of a specific strategy. * The function processes depositors until it runs out of gas. * @param _id The _id of the strategy for which to distribute shares. */ function distributeShares(uint _id) internal { EpochInfo storage epoch = _epochInfo[_id][ _strategyInfo[_id].lastProcessedEpoch ]; uint i = epoch.lastDepositorProcessed; uint sharesToDistribute = epoch.newShares; while (i < epoch.totDepositors && gasleft() > gasBuffer) { address investor = _depositors[_id][_strategyInfo[_id].lastProcessedEpoch][i]; uint depositInfo = _userInfoEpoch[_id][investor][ _strategyInfo[_id].lastProcessedEpoch ].depositInfo; uint dueShares = (sharesToDistribute * depositInfo) / epoch.totDepositedAssets; if (dueShares > 0) { // Transfer the shares _strategyInfo[_id].fundRepresentToken.safeTransfer( investor, dueShares ); } i++; } epoch.lastDepositorProcessed = i; } /** * @notice Distribute pending fees to the treasury addresses * @dev Internal function */ /// @param _id Strategy _id function sendPendingFees( uint _id ) external nonReentrant onlyOwner checkStrategyExistence(_id) { StrategyInfo storage strategy = _strategyInfo[_id]; require( block.timestamp >= strategy.lastFeeDistribution + strategy.feeDuration, "ERR_V.31" ); strategy.lastFeeDistribution = block.timestamp; uint pendingFees = strategy.pendingFees; require(pendingFees > 0, "ERR_V.35"); require( strategy.assetToken.balanceOf(address(this)) >= pendingFees, "ERR_V.32" ); strategy.pendingFees = 0; address addr0 = strategy.withdrawAddress[0]; address addr1 = strategy.withdrawAddress[1]; emit SendFeeWithOwner(_id, addr0, pendingFees / 2); emit SendFeeWithOwner(_id, addr1, pendingFees / 2); strategy.assetToken.safeTransfer(addr0, pendingFees / 2); strategy.assetToken.safeTransfer(addr1, pendingFees / 2); } /// @notice Withdraw ERC-20 Token to the owner /** * @dev Only Owner can call this function */ /// @param _tokenContract ERC-20 Token address function withdrawERC20(IERC20 _tokenContract) external onlyOwner { for (uint i = 0; i < strategiesCounter; i++) { require( _strategyInfo[i].guaranteeToken != _tokenContract, "ERR_V.34" ); require(_strategyInfo[i].assetToken != _tokenContract, "ERR_V.34"); } _tokenContract.safeTransfer( _msgSender(), _tokenContract.balanceOf(address(this)) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.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 Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(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"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.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.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead 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 ERC20 is Context, IERC20, IERC20Metadata { 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}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override 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 default value returned by this function, unless * it's overridden. * * 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 override 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: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, 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}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, 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}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, 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) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, 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) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This 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: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, 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: * * - `account` 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; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(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"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(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 Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - 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 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 {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ 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"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to * 0 before setting it to a non-zero value. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // 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 cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/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.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @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. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
//SPDX-License-Identifier: UNLICENSED pragma solidity >=0.5.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }
//SPDX-License-Identifier: UNLICENSED pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; /// @title TimeOracle /// @author Civilization /// @notice This contract is used to track periods of time based on a given epoch duration /// @dev The owner of the contract can change the epoch duration contract TimeOracle { address public owner; // Owner of the contract uint public startTime; // Start time of the tracking uint public epochDuration; // Duration of each period in seconds uint public currentPeriod; // Current periods elapsed from the start /// @notice Initializes the contract with a given epoch duration /// @param _epochDuration Duration of each period in seconds constructor(uint _epochDuration) { owner = msg.sender; // Set the deployer as the owner startTime = block.timestamp; // Initialization at deployment time epochDuration = _epochDuration; } /// @notice Calculates the start time for current period /// @return currentPeriodStartTime The start time for the current period function getCurrentPeriod() external view returns (uint currentPeriodStartTime) { require( block.timestamp >= startTime, "TimeOracle: Query before start time" ); // Calculate how many periods have passed since the start uint period = (block.timestamp - startTime) / epochDuration; // Calculate the start time for the current period currentPeriodStartTime = startTime + period * epochDuration; return currentPeriodStartTime; } /// @notice Allows the owner to set a new epoch duration /// @param _newEpochDuration The new epoch duration in seconds function setEpochDuration(uint _newEpochDuration) external { require( msg.sender == owner, "TimeOracle: Only owner can change epochDuration" ); // Calculate the current period before changing epochDuration currentPeriod += (block.timestamp - startTime) / epochDuration; // Update startTime to now startTime = block.timestamp; // Update epochDuration epochDuration = _newEpochDuration; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; /// @custom:security-contact [email protected] contract CIVFundShare is ERC20, Ownable { constructor(address _owner) ERC20("CIVFundShare", "XCIV") { _transferOwnership(_owner); } function mint(uint _amount) public onlyOwner returns (bool) { _mint(_msgSender(), _amount); return true; } function burn(uint _amount) public returns (bool) { _burn(_msgSender(), _amount); return true; } } contract CIVFundShareFactory { function createCIVFundShare() public returns (CIVFundShare) { CIVFundShare fundRepresentToken = new CIVFundShare(msg.sender); return fundRepresentToken; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.18; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; import "./dependencies/FixedPoint.sol"; import "./interfaces/ICivFund.sol"; import "./dependencies/UniswapV2OracleLibrary.sol"; import "./CIV-TimeOracle.sol"; ////////////////// ERROR CODES ////////////////// /* ERR_VG.1 = "Msg.sender is not the Vault"; ERR_VG.2 = "Can't get first pair"; ERR_VG.3 = "Can't get second pair"; ERR_VG.4 = "Epoch not yet expired"; ERR_VG.5 = "Nothing to withdraw"; ERR_VG.6 = "Wait for the previos epoch to settle before requesting withdraw"; */ contract CivVaultGetter is ReentrancyGuard { using SafeMath for uint; using FixedPoint for *; ICivVault public civVault; /// @notice Uniswap Factory address address public constant UNISWAP_FACTORY = 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f; // to be adjusted for mainnet /// @notice Wrapped ETH Address address public constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // to be adjusted for mainnet /// @notice Dead Address address public constant NULL_ADDRESS = 0x0000000000000000000000000000000000000000; /// @notice Uniswap TWAP Period uint public constant PERIOD = 24 hours; /// @notice Each Strategy Uniswap Pair Info List mapping(uint => PairInfo[]) public pairInfo; /// @notice Each Strategy time Oracle mapping(uint => TimeOracle) public timeOracle; modifier onlyVault() { require(msg.sender == address(civVault), "ERR_VG.1"); _; } constructor(address _civVaultAddress) { civVault = ICivVault(_civVaultAddress); } /// @notice Add new uniswap pair info to pairInfo list /// @dev Interal function /// @param _id Strategy Id /// @param _pair Uniswap Pair Interface function addPair(uint _id, IUniswapV2Pair _pair) internal { (, , uint32 blockTimestampLast) = _pair.getReserves(); ( uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp ) = UniswapV2OracleLibrary.currentCumulativePrices(address(_pair)); uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired FixedPoint.uq112x112 memory price0Average = FixedPoint.uq112x112( uint224( (price0Cumulative - _pair.price0CumulativeLast()) / timeElapsed ) ); FixedPoint.uq112x112 memory price1Average = FixedPoint.uq112x112( uint224( (price1Cumulative - _pair.price1CumulativeLast()) / timeElapsed ) ); pairInfo[_id].push( PairInfo({ pair: _pair, price0CumulativeLast: price0Cumulative, price1CumulativeLast: price1Cumulative, token0: _pair.token0(), token1: _pair.token1(), price0Average: price0Average, price1Average: price1Average, blockTimestampLast: blockTimestamp }) ); } /// @notice Deploy new Time Oracle for the strategy /// @param _id Strategy Id /// @param _epochDuration Epoch Duration function addTimeOracle(uint _id, uint _epochDuration) external onlyVault { timeOracle[_id] = new TimeOracle(_epochDuration); } /// @notice Add new uniswap pair info to pairInfo list from token pair address /// @param _id Strategy Id /// @param _token0 Token0 Address /// @param _token1 Token1 Address function addUniPair( uint _id, address _token0, address _token1 ) external nonReentrant onlyVault { IUniswapV2Factory factory = IUniswapV2Factory(UNISWAP_FACTORY); address pairAddress = factory.getPair(_token1, _token0); if (pairAddress == NULL_ADDRESS) { pairAddress = factory.getPair(_token1, WETH_ADDRESS); require(pairAddress != NULL_ADDRESS, "ERR_VG.2"); IUniswapV2Pair _pairA = IUniswapV2Pair(pairAddress); addPair(_id, _pairA); pairAddress = factory.getPair(_token0, WETH_ADDRESS); require(pairAddress != NULL_ADDRESS, "ERR_VG.3"); IUniswapV2Pair _pairB = IUniswapV2Pair(pairAddress); addPair(_id, _pairB); } else { IUniswapV2Pair _pair = IUniswapV2Pair(pairAddress); addPair(_id, _pair); } } /// @notice Update Uniswap LP token price /// @dev Anyone can call this function but we update price after PERIOD of time /// @param _id Strategy Id /** * @param _index PairInfo index * We can have 1 or 2 index * If Deposit/Guarantee Token Pair exists on uniswap there's only 1 pairInfo * If Deposit/Guarantee Token Pair does not exist on uniswap, we have 2 pairInfo * Deposit/WETH Pair and Guarantee/WETH token pair to get price */ function update(uint _id, uint _index) public { PairInfo storage info = pairInfo[_id][_index]; ( uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp ) = UniswapV2OracleLibrary.currentCumulativePrices(address(info.pair)); uint32 timeElapsed = blockTimestamp - info.blockTimestampLast; // overflow is desired // ensure that at least one full period has passed since the last update if (timeElapsed < PERIOD) return; // overflow is desired, casting never truncates // cumulative price is in (uq112x112 price * seconds) units so we simply wrap it after division by time elapsed info.price0Average = FixedPoint.uq112x112( uint224( (price0Cumulative - info.price0CumulativeLast) / timeElapsed ) ); info.price0CumulativeLast = price0Cumulative; info.price1Average = FixedPoint.uq112x112( uint224( (price1Cumulative - info.price1CumulativeLast) / timeElapsed ) ); info.price1CumulativeLast = price1Cumulative; info.blockTimestampLast = blockTimestamp; } /// @notice Update Uniswap LP token price for all pairs /// @dev Anyone can call this function but we update price after PERIOD of time /// @param _id Strategy Id function updateAll(uint _id) public { for (uint i = 0; i < pairInfo[_id].length; i++) update(_id, i); } /// @notice Set new epochDuration for Strategy /// @dev Only the Getter can call this function from timeOracle /// @param _id Strategy Id /// @param _newEpochDuration new epochDuration function setEpochDuration(uint _id, uint _newEpochDuration) public { timeOracle[_id].setEpochDuration(_newEpochDuration); } /** * @dev Get the current period for a Strategy * @param _id The ID of the Strategy * @return currentPeriodStartTime The end time for the current period */ function getCurrentPeriod( uint _id ) external view returns (uint currentPeriodStartTime) { return timeOracle[_id].getCurrentPeriod(); } /// @dev Get Guarantee amount for deposit to the vault /// @param _id Strategy Id /// @param _amount Amount to deposit in the vault /// @return amount Guarantee Token Amount needs for deposit in a given strategy function getDepositGuarantee( uint _id, uint _amount ) external view returns (uint) { return (getPrice(_id, _amount) * civVault.getStrategyInfo(_id).guaranteeFee) / civVault.feeBase(); } /// @dev Get available deposit amount based of user's guarantee amount /// @param _id Strategy Id /// @param _user User address /// @return amount Current Available Deposit amount regarding users's current guarantee token balance in a given strategy function getAllowedDeposit( uint _id, address _user ) external view returns (uint) { IERC20Extended guarantee = IERC20Extended( address(civVault.getStrategyInfo(_id).guaranteeToken) ); return (getReversePrice(_id, guarantee.balanceOf(_user)) * civVault.feeBase()) / civVault.getStrategyInfo(_id).guaranteeFee; } /// @dev Get Guarantee Token symbol and decimal /// @param _id Strategy Id /// @return symbol Guarantee Token Symbol in a given strategy /// @return decimals Guarantee Token Decimal in a given strategy function getGuaranteeTokenInfo( uint _id ) external view returns (string memory symbol, uint decimals) { IERC20Extended guarantee = IERC20Extended( address(civVault.getStrategyInfo(_id).guaranteeToken) ); symbol = guarantee.symbol(); decimals = guarantee.decimals(); } /// @dev Get claimable guarantee token amount /// @param _id Strategy Id /// @param _user userAddress /// @return amount Current claimable guarantee token amount function getClaimableGuaranteeToken( uint _id, address _user ) external view returns (uint) { StrategyInfo memory strategy = civVault.getStrategyInfo(_id); UserInfo memory user = civVault.getUserInfo(_id, _user); uint endIndex = user.numberOfLocks; uint unLocked; for (uint i = user.startingIndexGuarantee; i < endIndex; i++) { if ( block.timestamp < civVault.getGuaranteeInfo(_id, _user, i).lockStartTime + strategy.lockPeriod ) { break; } unLocked += civVault.getGuaranteeInfo(_id, _user, i).lockAmount; } return unLocked; } /** * @dev Retrieves the current balance of the user's guarantee token, fund representative token, and liquidity strategy token in a specific strategy. * @param _id The ID of the strategy from which to retrieve user balance information. * @param _user The user EOA * @return guaranteeBalance The balance of the user's guarantee token in the given strategy. * @return representTokenBalance The balance of the user's fund representative token in the given strategy. * @return assetTokenBalance The balance of the user's liquidity strategy token in the given strategy. * @return guaranteeAddress The contract address of the guarantee token in the given strategy. * @return representTokenAddress The contract address of the fund representative token in the given strategy. * @return assetTokenAddress The contract address of the liquidity strategy token in the given strategy. */ function getUserBalances( uint _id, address _user ) external view returns ( uint guaranteeBalance, uint representTokenBalance, uint assetTokenBalance, address guaranteeAddress, address representTokenAddress, address assetTokenAddress ) { guaranteeAddress = address( civVault.getStrategyInfo(_id).guaranteeToken ); IERC20 guarantee = IERC20(guaranteeAddress); guaranteeBalance = guarantee.balanceOf(_user); representTokenAddress = address( civVault.getStrategyInfo(_id).fundRepresentToken ); IERC20 representToken = IERC20(representTokenAddress); representTokenBalance = representToken.balanceOf(_user); assetTokenAddress = address(civVault.getStrategyInfo(_id).assetToken); IERC20 assetToken = IERC20(assetTokenAddress); assetTokenBalance = assetToken.balanceOf(_user); return ( guaranteeBalance, representTokenBalance, assetTokenBalance, guaranteeAddress, representTokenAddress, assetTokenAddress ); } /// @notice get net values for new VPS for a certain epoch /// @param _id Strategy Id /// @param _newVPS New Value Per Share /// @param _epochId Epoch Id /// @return _epochs array of unclaimed epochs function getNetValues( uint _id, uint _newVPS, uint _epochId ) public view returns (uint, uint) { EpochInfo memory epoch = civVault.getEpochInfo(_id, _epochId); StrategyInfo memory strategy = civVault.getStrategyInfo(_id); require( block.timestamp >= epoch.epochStartTime + epoch.duration, "ERR_VG.4" ); uint currentWithdrawAssets = _newVPS * epoch.totWithdrawnShares; uint decimals = uint(strategy.fundRepresentToken.decimals()); uint multiplier = 10 ** decimals; uint newShares = (epoch.totDepositedAssets * multiplier) / _newVPS; return (currentWithdrawAssets, newShares); } /// @notice get unclaimed withdrawed token epochs /// @param _id Strategy Id /// @return _epochs array of unclaimed epochs function getUnclaimedTokens( uint _id, address _user ) public view returns (uint) { uint lastEpoch = civVault.getUserInfo(_id, _user).lastEpoch; require(lastEpoch > 0, "ERR_VG.5"); EpochInfo memory epoch = civVault.getEpochInfo(_id, lastEpoch); require(epoch.VPS > 0, "ERR_VG.6"); uint withdrawInfo = civVault .getUserInfoEpoch(_id, _user, lastEpoch) .withdrawInfo; return (withdrawInfo * epoch.currentWithdrawAssets) / epoch.totWithdrawnShares; } /// @notice Get Price of the each strategy's guarantee token amount based on deposit token amount /// @dev Public Function /// @param _id Strategy Id /// @param _amountIn deposit token amount /// @return amountOut Price of the token1 in a given strategy function getPrice( uint _id, uint _amountIn ) public view virtual returns (uint amountOut) { StrategyInfo memory strategyInfo = civVault.getStrategyInfo(_id); PairInfo[] memory curPairInfo = pairInfo[_id]; if (curPairInfo.length == 1) { if (address(strategyInfo.assetToken) == curPairInfo[0].token0) amountOut = curPairInfo[0] .price0Average .mul(_amountIn) .decode144(); else amountOut = curPairInfo[0] .price1Average .mul(_amountIn) .decode144(); } else { FixedPoint.uq112x112 memory value; if (address(strategyInfo.guaranteeToken) == curPairInfo[0].token0) { value = curPairInfo[0].price1Average; } else { value = curPairInfo[0].price0Average; } if (address(strategyInfo.assetToken) == curPairInfo[1].token0) { value = value.muluq(curPairInfo[1].price1Average.reciprocal()); } else { value = value.muluq(curPairInfo[1].price0Average.reciprocal()); } amountOut = value.mul(_amountIn).decode144(); } } /// @notice Get Price of the each strategy's deposit token amount based on guarantee token amount /// @dev Public Function /// @param _id Strategy Id /// @param _amountIn guarantee token amount /// @return amountOut Price of the token0 in a given strategy function getReversePrice( uint _id, uint _amountIn ) public view virtual returns (uint amountOut) { StrategyInfo memory strategyInfo = civVault.getStrategyInfo(_id); PairInfo[] memory curPairInfo = pairInfo[_id]; if (curPairInfo.length == 1) { if (address(strategyInfo.guaranteeToken) == curPairInfo[0].token0) amountOut = curPairInfo[0] .price0Average .mul(_amountIn) .decode144(); else amountOut = curPairInfo[0] .price1Average .mul(_amountIn) .decode144(); } else { FixedPoint.uq112x112 memory value; if (address(strategyInfo.assetToken) == curPairInfo[0].token0) { value = curPairInfo[0].price1Average; } else { value = curPairInfo[0].price0Average; } if (address(strategyInfo.guaranteeToken) == curPairInfo[1].token0) { value = value.muluq(curPairInfo[1].price1Average.reciprocal()); } else { value = value.muluq(curPairInfo[1].price0Average.reciprocal()); } amountOut = value.mul(_amountIn).decode144(); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.4.0; import "./FullMath.sol"; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) library FixedPoint { // range: [0, 2**112 - 1] // resolution: 1 / 2**112 struct uq112x112 { uint224 _x; } // range: [0, 2**144 - 1] // resolution: 1 / 2**112 struct uq144x112 { uint256 _x; } uint8 public constant RESOLUTION = 112; uint256 public constant Q112 = 0x10000000000000000000000000000; // 2**112 uint256 private constant Q224 = 0x100000000000000000000000000000000000000000000000000000000; // 2**224 uint256 private constant LOWER_MASK = 0xffffffffffffffffffffffffffff; // decimal of UQ*x112 (lower 112 bits) // encode a uint112 as a UQ112x112 function encode(uint112 x) internal pure returns (uq112x112 memory) { return uq112x112(uint224(x) << RESOLUTION); } // encodes a uint144 as a UQ144x112 function encode144(uint144 x) internal pure returns (uq144x112 memory) { return uq144x112(uint256(x) << RESOLUTION); } // decode a UQ112x112 into a uint112 by truncating after the radix point function decode(uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } // decode a UQ144x112 into a uint144 by truncating after the radix point function decode144(uq144x112 memory self) internal pure returns (uint144) { return uint144(self._x >> RESOLUTION); } // multiply a UQ112x112 by a uint, returning a UQ144x112 // reverts on overflow function mul(uq112x112 memory self, uint256 y) internal pure returns (uq144x112 memory) { uint256 z = 0; require(y == 0 || (z = self._x * y) / y == self._x, 'FixedPoint::mul: overflow'); return uq144x112(z); } // multiply a UQ112x112 by an int and decode, returning an int // reverts on overflow function muli(uq112x112 memory self, int256 y) internal pure returns (int256) { uint256 z = FullMath.mulDiv(self._x, uint256(y < 0 ? -y : y), Q112); require(z < 2**255, 'FixedPoint::muli: overflow'); return y < 0 ? -int256(z) : int256(z); } // multiply a UQ112x112 by a UQ112x112, returning a UQ112x112 // lossy function muluq(uq112x112 memory self, uq112x112 memory other) internal pure returns (uq112x112 memory) { if (self._x == 0 || other._x == 0) { return uq112x112(0); } uint112 upper_self = uint112(self._x >> RESOLUTION); // * 2^0 uint112 lower_self = uint112(self._x & LOWER_MASK); // * 2^-112 uint112 upper_other = uint112(other._x >> RESOLUTION); // * 2^0 uint112 lower_other = uint112(other._x & LOWER_MASK); // * 2^-112 // partial products uint224 upper = uint224(upper_self) * upper_other; // * 2^0 uint224 lower = uint224(lower_self) * lower_other; // * 2^-224 uint224 uppers_lowero = uint224(upper_self) * lower_other; // * 2^-112 uint224 uppero_lowers = uint224(upper_other) * lower_self; // * 2^-112 // so the bit shift does not overflow require(upper <= type(uint112).max, 'FixedPoint::muluq: upper overflow'); // this cannot exceed 256 bits, all values are 224 bits uint256 sum = uint256(upper << RESOLUTION) + uppers_lowero + uppero_lowers + (lower >> RESOLUTION); // so the cast does not overflow require(sum <= type(uint224).max, 'FixedPoint::muluq: sum overflow'); return uq112x112(uint224(sum)); } // returns a UQ112x112 which represents the ratio of the numerator to the denominator // can be lossy function fraction(uint256 numerator, uint256 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, 'FixedPoint::fraction: division by zero'); if (numerator == 0) return FixedPoint.uq112x112(0); if (numerator <= type(uint144).max) { uint256 result = (numerator << RESOLUTION) / denominator; require(result <= type(uint224).max, 'FixedPoint::fraction: overflow'); return uq112x112(uint224(result)); } else { uint256 result = FullMath.mulDiv(numerator, Q112, denominator); require(result <= type(uint224).max, 'FixedPoint::fraction: overflow'); return uq112x112(uint224(result)); } } // take the reciprocal of a UQ112x112 // reverts on overflow // lossy function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) { require(self._x != 0, 'FixedPoint::reciprocal: reciprocal of zero'); require(self._x != 1, 'FixedPoint::reciprocal: overflow'); return uq112x112(uint224(Q224 / self._x)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. //uint256 twos = -denominator & denominator; uint256 twos = denominator & (~denominator + 1); // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "./FixedPoint.sol"; // library with helper methods for oracles that are concerned with computing average prices library UniswapV2OracleLibrary { using FixedPoint for *; // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] function currentBlockTimestamp() internal view returns (uint32) { return uint32(block.timestamp % 2 ** 32); } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices( address pair ) internal view returns (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast(); price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast(); // if time has elapsed since the last update on the pair, mock the accumulated price values (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves(); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; // counterfactual price1Cumulative += uint(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.18; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "../dependencies/FixedPoint.sol"; struct StrategyInfo { // Info on each strategy IERC20 assetToken; // Address of asset token e.g. USDT IERC20 guaranteeToken; // Guarantee Token address e.g. Stone ICivFundRT fundRepresentToken; // Fund Represent tokens for deposit in the strategy XCIV uint fee; // Strategy Fee Amount uint guaranteeFee; // Strategy Guarantee Fee Amount uint maxDeposit; // Strategy Max Deposit Amount per Epoch uint maxUsers; // Strategy Max User per Epoch uint minDeposit; // Strategy Min Deposit Amount uint epochDuration; // Duration of an Epoch uint lockPeriod; // Strategy Guarantee Token Lock Period uint feeDuration; // Fee withdraw period uint lastFeeDistribution; // Last timestamp of distribution uint lastProcessedEpoch; // Last Epoch Processed uint watermark; // Fee watermark uint pendingFees; // Pending fees that owner can withdraw address[] withdrawAddress; // Strategy Withdraw Address address investAddress; // Strategy Invest Address bool initialized; // Is strategy initialized? bool paused; // Flag that deposit is paused or not } struct EpochInfo { uint totDepositors; // Current depositors of the epoch uint totDepositedAssets; // Tot deposited asset in current epoch uint totWithdrawnShares; // Tot withdrawn asset in current epoch uint VPS; // VPS after rebalancing uint newShares; // New shares after rebalancing uint currentWithdrawAssets; // Withdrawn asset after rebalancing uint epochStartTime; // Epoch start time from time oracle uint lastDepositorProcessed; // Last depositor that has recived shares uint duration; } struct UserInfo { uint lastEpoch; // Last withdraw epoch uint startingIndexGuarantee; // Starting index of guarantee lock uint numberOfLocks; // Number of guarantee locks the user has } struct GuaranteeInfo { uint lockStartTime; // startTime of the guarantee lock uint lockAmount; // Amount of guarantee locked } struct UserInfoEpoch { uint depositInfo; uint withdrawInfo; uint depositIndex; uint epochGuaranteeIndex; bool hasDeposited; } struct AddStrategyParam { IERC20 _assetToken; IERC20 _guaranteeToken; uint _maxDeposit; uint _maxUsers; uint _minAmount; uint _fee; uint _guaranteeFee; uint _epochDuration; uint _lockPeriod; uint _feeDuration; address _investAddress; address[] _withdrawAddresses; bool _paused; } struct PairInfo { IUniswapV2Pair pair; //Uniswap Pair Address uint price0CumulativeLast; uint price1CumulativeLast; FixedPoint.uq112x112 price0Average; // First token average price FixedPoint.uq112x112 price1Average; // Second token average price uint32 blockTimestampLast; //Last time we calculate price address token0; // First token address address token1; // Second token address } interface ICivVault { function guaranteeFee() external view returns (uint); function feeBase() external view returns (uint); function getStrategyInfo( uint _id ) external view returns (StrategyInfo memory); function getEpochInfo( uint _id, uint _index ) external view returns (EpochInfo memory); function getCurrentEpoch(uint _id) external view returns (uint); function getUserInfo( uint _id, address _user ) external view returns (UserInfo memory); function getUserInfoEpoch( uint _id, address _user, uint _index ) external view returns (UserInfoEpoch memory); function getGuaranteeInfo( uint _idid, address _user, uint _index ) external view returns (GuaranteeInfo memory); } interface ICivFundRT is IERC20 { function decimals() external view returns (uint8); function mint(uint _amount) external returns (bool); function burn(uint _amount) external returns (bool); } interface ICivVaultGetter { function addUniPair(uint, address, address) external; function getPrice(uint, uint) external view returns (uint); function getReversePrice(uint, uint) external view returns (uint); function getBalanceOfUser(uint, address) external view returns (uint); function updateAll(uint) external; function addTimeOracle(uint, uint) external; function setEpochDuration(uint, uint) external; function getCurrentPeriod(uint) external view returns (uint); } interface IERC20Extended is IERC20 { function decimals() external view returns (uint); function symbol() external view returns (string memory); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxDeposit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"minDeposit","type":"uint256"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"},{"indexed":false,"internalType":"address[]","name":"withdrawAddress","type":"address[]"},{"indexed":false,"internalType":"address","name":"assetToken","type":"address"},{"indexed":false,"internalType":"address","name":"guaranteeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"lockPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeDuration","type":"uint256"}],"name":"AddStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CancelDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CancelWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"guaranteeAmount","type":"uint256"}],"name":"ClaimGuarantee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"ClaimWithdrawedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"InitializeStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"treasuryAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"SendFeeWithOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"SetEpochDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasBuffer","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasBuffer","type":"uint256"}],"name":"SetGasBuffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"SetGuaranteeFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldLocktime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLockTime","type":"uint256"}],"name":"SetGuaranteeLockTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"oldAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newAddress","type":"address"}],"name":"SetInvestAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldMaxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldMinAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldMaxUsers","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxUsers","type":"uint256"}],"name":"SetLimits","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"SetPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"oldAddress","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"newAddress","type":"address[]"}],"name":"SetWithdrawAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Update","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"VPS","type":"uint256"}],"name":"UpdateVPS","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"}],"name":"WithdrawedToken","type":"event"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"_assetToken","type":"address"},{"internalType":"contract IERC20","name":"_guaranteeToken","type":"address"},{"internalType":"uint256","name":"_maxDeposit","type":"uint256"},{"internalType":"uint256","name":"_maxUsers","type":"uint256"},{"internalType":"uint256","name":"_minAmount","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_guaranteeFee","type":"uint256"},{"internalType":"uint256","name":"_epochDuration","type":"uint256"},{"internalType":"uint256","name":"_lockPeriod","type":"uint256"},{"internalType":"uint256","name":"_feeDuration","type":"uint256"},{"internalType":"address","name":"_investAddress","type":"address"},{"internalType":"address[]","name":"_withdrawAddresses","type":"address[]"},{"internalType":"bool","name":"_paused","type":"bool"}],"internalType":"struct AddStrategyParam","name":"addStrategyParam","type":"tuple"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"cancelDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"cancelWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"claimGuaranteeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"claimWithdrawedTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"continueDistributingShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fundShareFactory","outputs":[{"internalType":"contract CIVFundShareFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getCurrentEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"getDepositors","outputs":[{"internalType":"address[]","name":"users","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getEpochInfo","outputs":[{"components":[{"internalType":"uint256","name":"totDepositors","type":"uint256"},{"internalType":"uint256","name":"totDepositedAssets","type":"uint256"},{"internalType":"uint256","name":"totWithdrawnShares","type":"uint256"},{"internalType":"uint256","name":"VPS","type":"uint256"},{"internalType":"uint256","name":"newShares","type":"uint256"},{"internalType":"uint256","name":"currentWithdrawAssets","type":"uint256"},{"internalType":"uint256","name":"epochStartTime","type":"uint256"},{"internalType":"uint256","name":"lastDepositorProcessed","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"internalType":"struct EpochInfo","name":"epoch","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getGuaranteeInfo","outputs":[{"components":[{"internalType":"uint256","name":"lockStartTime","type":"uint256"},{"internalType":"uint256","name":"lockAmount","type":"uint256"}],"internalType":"struct GuaranteeInfo","name":"userGuarantee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getStrategyInfo","outputs":[{"components":[{"internalType":"contract IERC20","name":"assetToken","type":"address"},{"internalType":"contract IERC20","name":"guaranteeToken","type":"address"},{"internalType":"contract ICivFundRT","name":"fundRepresentToken","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"guaranteeFee","type":"uint256"},{"internalType":"uint256","name":"maxDeposit","type":"uint256"},{"internalType":"uint256","name":"maxUsers","type":"uint256"},{"internalType":"uint256","name":"minDeposit","type":"uint256"},{"internalType":"uint256","name":"epochDuration","type":"uint256"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"},{"internalType":"uint256","name":"feeDuration","type":"uint256"},{"internalType":"uint256","name":"lastFeeDistribution","type":"uint256"},{"internalType":"uint256","name":"lastProcessedEpoch","type":"uint256"},{"internalType":"uint256","name":"watermark","type":"uint256"},{"internalType":"uint256","name":"pendingFees","type":"uint256"},{"internalType":"address[]","name":"withdrawAddress","type":"address[]"},{"internalType":"address","name":"investAddress","type":"address"},{"internalType":"bool","name":"initialized","type":"bool"},{"internalType":"bool","name":"paused","type":"bool"}],"internalType":"struct StrategyInfo","name":"strategy","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserInfo","outputs":[{"components":[{"internalType":"uint256","name":"lastEpoch","type":"uint256"},{"internalType":"uint256","name":"startingIndexGuarantee","type":"uint256"},{"internalType":"uint256","name":"numberOfLocks","type":"uint256"}],"internalType":"struct UserInfo","name":"user","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getUserInfoEpoch","outputs":[{"components":[{"internalType":"uint256","name":"depositInfo","type":"uint256"},{"internalType":"uint256","name":"withdrawInfo","type":"uint256"},{"internalType":"uint256","name":"depositIndex","type":"uint256"},{"internalType":"uint256","name":"epochGuaranteeIndex","type":"uint256"},{"internalType":"bool","name":"hasDeposited","type":"bool"}],"internalType":"struct UserInfoEpoch","name":"userEpochStruct","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"initializeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"processDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_newVPS","type":"uint256"}],"name":"rebalancing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"sendPendingFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_newDuration","type":"uint256"}],"name":"setEpochDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_newMaxDeposit","type":"uint256"},{"internalType":"uint256","name":"_newMinDeposit","type":"uint256"},{"internalType":"uint256","name":"_newMaxUsers","type":"uint256"}],"name":"setEpochLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_newFee","type":"uint256"},{"internalType":"uint256","name":"_newDuration","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasBuffer","type":"uint256"}],"name":"setGasBuffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_newAddress","type":"address"}],"name":"setInvestAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_lockTime","type":"uint256"},{"internalType":"uint256","name":"_newFee","type":"uint256"}],"name":"setStrategyGuarantee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address[]","name":"_newAddress","type":"address[]"}],"name":"setWithdrawAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategiesCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultGetter","outputs":[{"internalType":"contract ICivVaultGetter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenContract","type":"address"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001d33620000c5565b600180556040516000903090620000349062000115565b6001600160a01b039091168152602001604051809103906000f08015801562000061573d6000803e3d6000fd5b509050604051620000729062000123565b604051809103906000f0801580156200008f573d6000803e3d6000fd5b50600580546001600160a01b039283166001600160a01b0319918216179091556004805493909216921691909117905562000131565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b613a4a806200549183390190565b6110338062008edb83390190565b61535080620001416000396000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c806395ba658511610125578063d8808306116100ad578063e834edd81161007c578063e834edd81461055d578063f2fde38b1461058b578063f41fc3091461059e578063f4f3b200146105b1578063fc5358e8146105c457600080fd5b8063d880830614610504578063daff97b514610517578063db089e791461052a578063e2bbb1581461054a57600080fd5b80639f01f7ba116100f45780639f01f7ba14610442578063ae51accb14610455578063b0b1f9e9146104d5578063c602e48e146104e8578063c6a1c131146104f157600080fd5b806395ba6585146103bc57806395e911a81461041357806396bda2841461041c57806398f3fc571461042f57600080fd5b80634aad6b22116101a857806372fada5c1161017757806372fada5c1461035f5780637fae6d4d14610372578063813e6241146103855780638550c908146103985780638da5cb5b146103ab57600080fd5b80634aad6b221461031e5780635b65b9ab146103315780635d7035c614610344578063715018a61461035757600080fd5b80633fdefa6e116101ef5780633fdefa6e146102ae578063404f4e0d146102c5578063441a3e70146102e557806345a7f794146102f8578063481c1d8e1461030b57600080fd5b80631069f3b514610221578063179aa0401461025b5780631aa277a514610270578063282570f01461029b575b600080fd5b61023461022f3660046149dc565b6105d7565b60408051825181526020808401519082015291810151908201526060015b60405180910390f35b61026e610269366004614a0c565b610670565b005b600454610283906001600160a01b031681565b6040516001600160a01b039091168152602001610252565b61026e6102a9366004614a25565b6109a8565b6102b760025481565b604051908152602001610252565b6102d86102d3366004614a25565b610a9d565b6040516102529190614a8b565b61026e6102f3366004614a25565b610bb7565b61026e610306366004614aa5565b610e51565b61026e610319366004614bc9565b610f1d565b61026e61032c366004614a0c565b61146a565b61026e61033f366004614cd7565b611729565b6102b7610352366004614a0c565b6117d8565b61026e61184c565b61026e61036d366004614a0c565b611860565b61026e610380366004614a0c565b611cb5565b61026e6103933660046149dc565b611d4c565b61026e6103a6366004614a25565b611e5a565b6000546001600160a01b0316610283565b6103cf6103ca366004614d03565b6121bd565b6040516102529190600060a0820190508251825260208301516020830152604083015160408301526060830151606083015260808301511515608083015292915050565b6102b761271081565b61026e61042a366004614a0c565b612282565b600554610283906001600160a01b031681565b61026e610450366004614a0c565b6124de565b610468610463366004614a25565b6126dc565b6040516102529190600061012082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b61026e6104e3366004614a0c565b6127fa565b6102b760035481565b61026e6104ff366004614d3b565b612aa6565b61026e610512366004614a0c565b612c4f565b61026e610525366004614d82565b612dd4565b61053d610538366004614a0c565b612e67565b6040516102529190614da7565b61026e610558366004614a25565b6130a3565b61057061056b366004614d03565b613597565b60408051825181526020928301519281019290925201610252565b61026e610599366004614eef565b613617565b61026e6105ac366004614a0c565b61368d565b61026e6105bf366004614eef565b6136d6565b61026e6105d2366004614cd7565b613826565b6105fb60405180606001604052806000815260200160008152602001600081525090565b8280600354116106265760405162461bcd60e51b815260040161061d90614f0c565b60405180910390fd5b505060009182526008602090815260408084206001600160a01b03909316845291815291819020815160608101835281548152600182015493810193909352600201549082015290565b61067861390c565b80806003541161069a5760405162461bcd60e51b815260040161061d90614f0c565b60008281526009602052604090205482906106c75760405162461bcd60e51b815260040161061d90614f2d565b600083815260066020818152604080842081516102608101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a08201529381015460c0850152600781015460e085015260088101546101008501526009810154610120850152600a810154610140850152600b810154610160850152600c810154610180850152600d8101546101a0850152600e8101546101c0850152600f8101805483518186028101860190945280845291936101e086019392908301828280156107db57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107bd575b5050509183525050601091909101546001600160a01b03811660208084019190915260ff600160a01b830481161515604080860191909152600160a81b909304161515606090930192909252600087815260089092528120919250908161083f3390565b6001600160a01b03168152602081019190915260400160009081206002810154600182015491935091815b838110156108fa5761012086015160008a8152600c6020908152604080832033845282528083208584529091529020546108a49190614f65565b42106108fa576000898152600c6020908152604080832033845282528083208484529091529020600101546108d99083614f65565b91506108e6816001614f65565b9250806108f281614f7e565b91505061086a565b50600081116109365760405162461bcd60e51b81526020600482015260086024820152674552525f562e313960c01b604482015260640161061d565b600184018290556109563360208701516001600160a01b03169083613965565b6040805189815233602082015280820183905290517ffccb8ae12beda66b6d00eeb9e618561189d5f249c36ccad81909d3bb554d58db9181900360600190a1505050505050506109a560018055565b50565b6109b06139cd565b8180600354116109d25760405162461bcd60e51b815260040161061d90614f0c565b600083815260066020908152604091829020600801548251868152918201529081018390527fc8cebf046c3a3799bf1206980180c44983f298221ad03c0fe827ab5c5c0a398c9060600160405180910390a160048054604051630282570f60e41b8152918201859052602482018490526001600160a01b03169063282570f090604401600060405180830381600087803b158015610a6f57600080fd5b505af1158015610a83573d6000803e3d6000fd5b505050600093845250506006602052604090912060080155565b6060828060035411610ac15760405162461bcd60e51b815260040161061d90614f0c565b600084815260076020908152604080832086845290915290205467ffffffffffffffff811115610af357610af3614ad7565b604051908082528060200260200182016040528015610b1c578160200160208202803683370190505b50915060005b6000858152600760209081526040808320878452909152902054811015610baf576000858152600b60209081526040808320878452825280832084845290915290205483516001600160a01b0390911690849083908110610b8557610b85614f97565b6001600160a01b039092166020928302919091019091015280610ba781614f7e565b915050610b22565b505092915050565b610bbf61390c565b818060035411610be15760405162461bcd60e51b815260040161061d90614f0c565b6000838152600960205260409020548390610c0e5760405162461bcd60e51b815260040161061d90614f2d565b6000848152600660205260408120600201546001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c979190614fad565b905083811015610cd45760405162461bcd60e51b81526020600482015260086024820152674552525f562e323560c01b604482015260640161061d565b6000610cdf866117d8565b600087815260076020908152604080832084845290915290206008810154600690910154919250610d0f91614f65565b421115610d2e5760405162461bcd60e51b815260040161061d90614fc6565b6000868152600a602090815260408083203380855290835281842085855283528184208a8552600884528285209185529252909120805415801590610d7557506001820154155b15610d88578054610d8890899033613a27565b600088815260076020908152604080832086845290915281206002018054899290610db4908490614f65565b9250508190555086826001016000828254610dcf9190614f65565b909155505080548314610de0578281555b610e073360008a8152600660205260409020600201546001600160a01b031690308a613b6b565b604051878152889033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a3505050505050610e4d60018055565b5050565b610e596139cd565b838060035411610e7b5760405162461bcd60e51b815260040161061d90614f0c565b60008581526006602081815260409283902060058101546007820154919093015484518a81529283019390935292810187905260608101929092526080820185905260a082015260c081018390527fe688636a9e39148b1edbd6665d6d4a56d8629d5047d44472c5d06bca67f90a4f9060e00160405180910390a150600093845260066020819052604090942060058101939093556007830191909155910155565b610f2561390c565b610f2d6139cd565b80610160015151600214610f6d5760405162461bcd60e51b81526020600482015260076024820152664552525f562e3360c81b604482015260640161061d565b60208101516001600160a01b0316610fb15760405162461bcd60e51b81526020600482015260076024820152664552525f562e3560c81b604482015260640161061d565b60006001600160a01b0316816101600151600081518110610fd457610fd4614f97565b60200260200101516001600160a01b03160361101c5760405162461bcd60e51b815260206004820152600760248201526622a9292fab171b60c91b604482015260640161061d565b60006001600160a01b031681610160015160018151811061103f5761103f614f97565b60200260200101516001600160a01b0316036110875760405162461bcd60e51b81526020600482015260076024820152664552525f562e3760c81b604482015260640161061d565b60055460408051636621387d60e01b815290516000926001600160a01b031691636621387d916004808301926020929190829003018187875af11580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190614fe8565b905060405180610260016040528083600001516001600160a01b0316815260200183602001516001600160a01b03168152602001826001600160a01b031681526020018360a0015181526020018360c0015181526020018360400151815260200183606001518152602001836080015181526020018360e001518152602001836101000151815260200183610120015181526020016000815260200160008152602001600081526020016000815260200183610160015181526020018361014001516001600160a01b03168152602001600015158152602001836101800151151581525060066000600354815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e082015181600701556101008201518160080155610120820151816009015561014082015181600a015561016082015181600b015561018082015181600c01556101a082015181600d01556101c082015181600e01556101e082015181600f01908051906020019061131292919061493d565b5061020082015160109091018054610220840151610240909401511515600160a81b0260ff60a81b19941515600160a01b026001600160a81b03199092166001600160a01b0390941693909317179290921617905560038054908190600061137983614f7e565b9091555050600480548451602086015160405163121f2aaf60e21b81529384018590526001600160a01b03918216602485015281166044840152169063487caabc90606401600060405180830381600087803b1580156113d857600080fd5b505af11580156113ec573d6000803e3d6000fd5b505050508260a00151817f7fd83957c6ca0ef0e76db72271f206d0e451f24ed6ae9f86da9d4c888253a1f48560400151866080015187610180015188610160015189600001518a602001518b61010001518c6101200151604051611457989796959493929190615005565b60405180910390a350506109a560018055565b61147261390c565b61147a6139cd565b80806003541161149c5760405162461bcd60e51b815260040161061d90614f0c565b6000828152600660205260409020600a810154600b8201546114be9190614f65565b4210156114f85760405162461bcd60e51b81526020600482015260086024820152674552525f562e333160c01b604482015260640161061d565b42600b820155600e8101548061153b5760405162461bcd60e51b81526020600482015260086024820152674552525f562e333560c01b604482015260640161061d565b81546040516370a0823160e01b815230600482015282916001600160a01b0316906370a0823190602401602060405180830381865afa158015611582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a69190614fad565b10156115df5760405162461bcd60e51b815260206004820152600860248201526722a9292fab17199960c11b604482015260640161061d565b6000600e8301819055600f8301805482906115fc576115fc614f97565b6000918252602082200154600f850180546001600160a01b03909216935090600190811061162c5761162c614f97565b6000918252602090912001546001600160a01b031690507f783ad58a3e77de8f48cbc5b7b85e67eda94545ca6ac909671c4d4461eedecc56868361167160028761505e565b604080519384526001600160a01b0390921660208401529082015260600160405180910390a17f783ad58a3e77de8f48cbc5b7b85e67eda94545ca6ac909671c4d4461eedecc5686826116c560028761505e565b604080519384526001600160a01b0390921660208401529082015260600160405180910390a161170c826116fa60028661505e565b86546001600160a01b03169190613965565b61171b816116fa60028661505e565b50505050506109a560018055565b6117316139cd565b8280600354116117535760405162461bcd60e51b815260040161061d90614f0c565b6000848152600660209081526040918290206003810154600a9091015483518881529283019190915281830186905260608201526080810184905290517f7eb9abb1c530a0c5c9e6a557c080514b3d38d59cb1d2a0fc085405d67f991a029181900360a00190a1506000928352600660205260409092206003810191909155600a0155565b60008180600354116117fc5760405162461bcd60e51b815260040161061d90614f0c565b60008381526009602052604090205483906118295760405162461bcd60e51b815260040161061d90614f2d565b60008481526009602052604090205461184490600190615080565b949350505050565b6118546139cd565b61185e6000613ba3565b565b61186861390c565b80806003541161188a5760405162461bcd60e51b815260040161061d90614f0c565b60008281526009602052604090205482906118b75760405162461bcd60e51b815260040161061d90614f2d565b6000838152600660205260408120906118cf856117d8565b600086815260076020908152604080832084845290915290206008810154600682015492935090916119019190614f65565b421061193a5760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c8d60c21b604482015260640161061d565b6000868152600a602090815260408083203384528252808320858452909152902080548061197a5760405162461bcd60e51b815260040161061d90615093565b6000808355600184018054839290611993908490615080565b909155505084546119ae906001600160a01b03163383613965565b60008881526008602090815260408083203384529091528120600384015490919081905b8360020154811015611a2f5760008c8152600c602090815260408083203384528252808320848452909152902060010154611a0d9084614f65565b925081611a1981614f7e565b9250508080611a2790614f7e565b9150506119d2565b5080836002016000828254611a449190615080565b90915550506001880154611a62906001600160a01b03163384613965565b60008b8152600b602090815260408083208a845282528083206002890154845290915280822054885483529120546001600160a01b03918216911603611ad75760008b8152600b602090815260408083208a8452825280832089548452909152902080546001600160a01b0319169055611c3a565b6000600b60008d8152602001908152602001600020600089815260200190815260200160002060008860000154815260200190815260200160002060009054906101000a90046001600160a01b031690506000600b60008e815260200190815260200160002060008a815260200190815260200160002060008960000154815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080600b60008e815260200190815260200160002060008a815260200190815260200160002060008860020154815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508560020154600a60008e81526020019081526020016000206000836001600160a01b03166001600160a01b0316815260200190815260200160002060008a815260200190815260200160002060020181905550505b6000600286018190558654908790611c51836150b5565b909155505060048501805460ff1916905560408051338152602081018d905280820186905290517f4d03849d7cc7e6aa8812404182c6821dda42bc4a15e60a2055dee048bff349109181900360600190a1505050505050505050506109a560018055565b611cbd61390c565b808060035411611cdf5760405162461bcd60e51b815260040161061d90614f0c565b60008281526008602090815260408083203384529091529020805480611d325760405162461bcd60e51b815260206004820152600860248201526722a9292fab17199b60c11b604482015260640161061d565b611d3d848233613a27565b5060009055506109a560018055565b611d546139cd565b818060035411611d765760405162461bcd60e51b815260040161061d90614f0c565b6001600160a01b038216611db75760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c4d60c21b604482015260640161061d565b600083815260066020526040908190206010015490517f94c8b3c75ba308c40e2ac10a7a6e9e5ff5c689a07cddb9a6b7a1227682e4728391611e209186916001600160a01b03169086909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a15060009182526006602052604090912060100180546001600160a01b0319166001600160a01b03909216919091179055565b611e6261390c565b611e6a6139cd565b818060035411611e8c5760405162461bcd60e51b815260040161061d90614f0c565b600083815260066020526040902060108101546001600160a01b0316611edf5760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c4d60c21b604482015260640161061d565b80600c015460000361204d5760008481526007602090815260408083208380529091529020600381015415612005578054600782015414611f4d5760405162461bcd60e51b815260206004820152600860248201526722a9292fab17189b60c11b604482015260640161061d565b600085815260096020526040902054600110611f965760405162461bcd60e51b81526020600482015260086024820152674552525f562e313760c01b604482015260640161061d565b600c82018054906000611fa883614f7e565b9091555050600085815260076020908152604080832060018452909152902060088101546006820154611fdb9190614f65565b421015611ffa5760405162461bcd60e51b815260040161061d906150cc565b600301849055612047565b806008015481600601546120199190614f65565b4210156120385760405162461bcd60e51b815260040161061d906150cc565b600d8201849055600381018490555b50612162565b6000848152600760208181526040808420600c86015485529091529091208054910154146120a85760405162461bcd60e51b815260206004820152600860248201526722a9292fab17189b60c11b604482015260640161061d565b600c810180549060006120ba83614f7e565b9091555050600c8101546000858152600960205260409020541161210b5760405162461bcd60e51b81526020600482015260086024820152674552525f562e313760c01b604482015260640161061d565b6000848152600760209081526040808320600c850154845290915290206008810154600682015461213c9190614f65565b42101561215b5760405162461bcd60e51b815260040161061d906150cc565b6003018390555b61216c8484613bf3565b600c81015460408051868152602081019290925281018490527f0215487829526ab31001252991ed70c90a9a6aaefa14f9ee2bda4b64db3bbf7a9060600160405180910390a15050610e4d60018055565b6121f16040518060a00160405280600081526020016000815260200160008152602001600081526020016000151581525090565b8380600354116122135760405162461bcd60e51b815260040161061d90614f0c565b50506000928352600a602090815260408085206001600160a01b03909416855292815282842091845290815291819020815160a08101835281548152600182015493810193909352600281015491830191909152600381015460608301526004015460ff161515608082015290565b61228a6139cd565b8080600354116122ac5760405162461bcd60e51b815260040161061d90614f0c565b600082815260066020526040902060100154600160a01b900460ff16156122ff5760405162461bcd60e51b81526020600482015260076024820152664552525f562e3960c81b604482015260640161061d565b6000828152600660205260409081902060108101805460ff60a01b1916600160a01b17905560048054600890920154925163ddaf8d0760e01b81526001600160a01b039092169263ddaf8d07926123629287929101918252602082015260400190565b600060405180830381600087803b15801561237c57600080fd5b505af1158015612390573d6000803e3d6000fd5b5050505060405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200142815260200160008152602001600660008581526020019081526020016000206008015481525060076000848152602001908152602001600020600060096000868152602001908152602001600020548152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e0820151816007015561010082015181600801559050506009600083815260200190815260200160002060008154809291906124aa90614f7e565b909155505060405182907f74e534d9ee9babee8812594b75f57a2889a16ee1b6c28c2de11b5afffad02b8390600090a25050565b6124e661390c565b8080600354116125085760405162461bcd60e51b815260040161061d90614f0c565b60008281526009602052604090205482906125355760405162461bcd60e51b815260040161061d90614f2d565b60008381526006602052604081209061254d856117d8565b6000868152600760209081526040808320848452909152902060088101546006820154929350909161257f9190614f65565b42106125b85760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c8d60c21b604482015260640161061d565b6000868152600a602090815260408083203380855290835281842086855283528184208a855260088452828520918552925290912060018201548061260f5760405162461bcd60e51b815260040161061d90615093565b600060018401819055825560028401548111156126595760405162461bcd60e51b815260206004820152600860248201526722a9292fab17191b60c11b604482015260640161061d565b8084600201600082825461266d9190615080565b9091555050600286015461268b906001600160a01b03163383613965565b60408051338152602081018b905280820183905290517f39e2e01794006bc1f63835af5c05db790beca4bfb40de3f02cc3ddf22dccc0fb9181900360600190a150505050505050506109a560018055565b61272b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b82806003541161274d5760405162461bcd60e51b815260040161061d90614f0c565b600084815260096020526040902054849061277a5760405162461bcd60e51b815260040161061d90614f2d565b505050600091825260076020818152604080852093855292815292829020825161012081018452815481526001820154948101949094526002810154928401929092526003820154606084015260048201546080840152600582015460a0840152600682015460c084015281015460e08301526008015461010082015290565b61280261390c565b61280a6139cd565b80806003541161282c5760405162461bcd60e51b815260040161061d90614f0c565b600082815260066020818152604080842081516102608101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a08201529381015460c0850152600781015460e085015260088101546101008501526009810154610120850152600a810154610140850152600b810154610160850152600c810154610180850152600d8101546101a0850152600e8101546101c0850152600f8101805483518186028101860190945280845291936101e0860193929083018282801561294057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612922575b5050509183525050601091909101546001600160a01b03811660208084019190915260ff600160a01b830481161515604080860191909152600160a81b90930416151560609384015260008781526007808352838220610180870151835283529083902083516101208101855281548152600182015493810193909352600281015493830193909352600383015493820184905260048301546080830152600583015460a0830152600683015460c083015282015460e0820152600890910154610100820152919250612a405760405162461bcd60e51b81526020600482015260086024820152674552525f562e323760c01b604482015260640161061d565b60e081015115612a7d5760405162461bcd60e51b815260206004820152600860248201526708aa4a4beac5c64760c31b604482015260640161061d565b8060200151600003612a90575050612a9c565b612a998461426f565b50505b506109a560018055565b612aae6139cd565b818060035411612ad05760405162461bcd60e51b815260040161061d90614f0c565b8151600214612b0b5760405162461bcd60e51b81526020600482015260076024820152664552525f562e3360c81b604482015260640161061d565b60006001600160a01b031682600081518110612b2957612b29614f97565b60200260200101516001600160a01b031603612b715760405162461bcd60e51b815260206004820152600760248201526622a9292fab171b60c91b604482015260640161061d565b60006001600160a01b031682600181518110612b8f57612b8f614f97565b60200260200101516001600160a01b031603612bd75760405162461bcd60e51b81526020600482015260076024820152664552525f562e3760c81b604482015260640161061d565b6000838152600660205260409081902090517f13f42559ce1a76db34ac3c5b7141308c1e286e00168793042025be3e556bfc5591612c1c918691600f019086906150ee565b60405180910390a160008381526006602090815260409091208351612c4992600f9092019185019061493d565b50505050565b612c5761390c565b612c5f6139cd565b808060035411612c815760405162461bcd60e51b815260040161061d90614f0c565b60008281526007602081815260408084206006808452828620600c01548652908352938190208151610120810183528154815260018201549381019390935260028101549183019190915260038101546060830181905260048201546080840152600582015460a08401529381015460c08301529182015460e082015260089091015461010082015290612d425760405162461bcd60e51b81526020600482015260086024820152674552525f562e323760c01b604482015260640161061d565b8060e00151600003612d815760405162461bcd60e51b81526020600482015260086024820152674552525f562e323960c01b604482015260640161061d565b805160e082015110612dc05760405162461bcd60e51b815260206004820152600860248201526704552525f562e33360c41b604482015260640161061d565b612dc98361426f565b50506109a560018055565b612ddc6139cd565b818060035411612dfe5760405162461bcd60e51b815260040161061d90614f0c565b6040805184815283151560208201527f77f1fcfcce67dc392d64f842056d2ec06c80986c47c910f7e79c5b23a2738d74910160405180910390a1506000918252600660205260409091206010018054911515600160a81b0260ff60a81b19909216919091179055565b612f2460405180610260016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016060815260200160006001600160a01b031681526020016000151581526020016000151581525090565b818060035411612f465760405162461bcd60e51b815260040161061d90614f0c565b60008381526006602081815260409283902083516102608101855281546001600160a01b0390811682526001830154811682850152600283015416818601526003820154606082015260048201546080820152600582015460a08201529281015460c0840152600781015460e084015260088101546101008401526009810154610120840152600a810154610140840152600b810154610160840152600c810154610180840152600d8101546101a0840152600e8101546101c0840152600f81018054855181850281018501909652808652939491936101e086019383018282801561305b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161303d575b5050509183525050601091909101546001600160a01b038116602083015260ff600160a01b8204811615156040840152600160a81b9091041615156060909101529392505050565b6130ab61390c565b8180600354116130cd5760405162461bcd60e51b815260040161061d90614f0c565b600083815260066020526040902060100154600160a81b900460ff16156131205760405162461bcd60e51b815260206004820152600760248201526622a9292fab171960c91b604482015260640161061d565b6000838152600660205260409020600781015483116131515760405162461bcd60e51b815260040161061d90615093565b805483906001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156131a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131cc9190614fad565b10156132055760405162461bcd60e51b81526020600482015260086024820152674552525f562e323160c01b604482015260640161061d565b6000613210856117d8565b600086815260076020908152604080832084845290915290206008810154600682015492935090916132429190614f65565b4211156132615760405162461bcd60e51b815260040161061d90614fc6565b6000868152600a602090815260408083203380855290835281842086855283528184208a8552600884528285209185529252909120600585015460018401546132ab908990614f65565b11156132e45760405162461bcd60e51b81526020600482015260086024820152674552525f562e323360c01b604482015260640161061d565b6004805460405163a616f34560e01b81529182018a90526001600160a01b03169063a616f34590602401600060405180830381600087803b15801561332857600080fd5b505af115801561333c573d6000803e3d6000fd5b505050506004858101548154604051635cf4ee9160e01b81529283018b9052602483018a905260009261271092916001600160a01b031690635cf4ee9190604401602060405180830381865afa15801561339a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133be9190614fad565b6133c8919061515d565b6133d2919061505e565b90506133ee3360018801546001600160a01b0316903084613b6b565b6000898152600c602090815260408083203384528252808320600286015484529091528120600385015490910361342a57600283015460038501555b60028301805490600061343c83614f7e565b909155505042815560018101829055600484015460ff166134fe5760068701548554613469906001614f65565b11156134a25760405162461bcd60e51b815260206004820152600860248201526722a9292fab17191960c11b604482015260640161061d565b60008a8152600b60209081526040808320898452825280832088548452909152812080546001600160a01b031916331790558554600286018190559086906134e983614f7e565b909155505060048401805460ff191660011790555b888560010160008282546135129190614f65565b9091555050865461352e906001600160a01b031633308c613b6b565b888460000160008282546135429190614f65565b909155505060408051308152602081018b905281518c9233927fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7929081900390910190a35050505050505050610e4d60018055565b60408051808201909152600080825260208201528380600354116135cd5760405162461bcd60e51b815260040161061d90614f0c565b50506000928352600c602090815260408085206001600160a01b03909416855292815282842091845290815291819020815180830190925280548252600101549181019190915290565b61361f6139cd565b6001600160a01b0381166136845760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161061d565b6109a581613ba3565b6136956139cd565b60025460408051918252602082018390527f3e8b961c6e8faa03d0d285994a4dade0cf480a9fedd1c35c093d5d4f0a3ed061910160405180910390a1600255565b6136de6139cd565b60005b6003548110156137a8576000818152600660205260409020600101546001600160a01b038084169116036137425760405162461bcd60e51b815260206004820152600860248201526711549497d58b8ccd60c21b604482015260640161061d565b6000818152600660205260409020546001600160a01b038084169116036137965760405162461bcd60e51b815260206004820152600860248201526711549497d58b8ccd60c21b604482015260640161061d565b806137a081614f7e565b9150506136e1565b506109a5336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156137f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138159190614fad565b6001600160a01b0384169190613965565b61382e6139cd565b8280600354116138505760405162461bcd60e51b815260040161061d90614f0c565b600084815260066020908152604091829020600901548251878152918201529081018490527f1b4a3d3abd483e39f6952818ff6bf53403dbeee05ef875088ed214b3c7fdb1049060600160405180910390a16000848152600660209081526040918290206004015482519081529081018490527fa984efc2bef6d7e91d9620c90f6f42b4cfb5913bf1db59801626e4a8eabacb38910160405180910390a150600092835260066020526040909220600981019190915560040155565b60026001540361395e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161061d565b6002600155565b6040516001600160a01b0383166024820152604481018290526139c890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614371565b505050565b6000546001600160a01b0316331461185e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161061d565b60008381526007602090815260408083208584528252808320868452600a83528184206001600160a01b0386168552835281842086855290925282206001015490918115613af15760008360020154846005015484613a86919061515d565b613a90919061505e565b9050613a9c8183614f65565b604080518981526001600160a01b0388166020820152908101889052606081018390529092507f25d1255c398e637e957d1d04691db7d1b318bc88e20deda96f2c8714f8297e389060800160405180910390a1505b8015613b1a57600086815260066020526040902054613b1a906001600160a01b03168583613965565b604080518781526001600160a01b03861660208201529081018290527ffd8c040503c4beb434790f3a2e972438d06ece0dc342f58052f2f9fd385828779060600160405180910390a1505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612c499085906323b872dd60e01b90608401613991565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008111613c2e5760405162461bcd60e51b81526020600482015260086024820152674552525f562e333560c01b604482015260640161061d565b6000613c3a8383614446565b60008581526007602081815260408084206006808452828620600c8101548088529285528387208c885282865284516102608101865282546001600160a01b0390811682526001840154811682890152600284015416818701526003830154606082015260048301546080820152600583015460a08201529282015460c08401529581015460e083015260088101546101008301526009810154610120830152600a810154610140830152600b810154610160830152610180820192909252600d8201546101a0820152600e8201546101c0820152600f82018054845181870281018701909552808552989a5096985093969495939490936101e0860193909190830182828015613d7457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613d56575b5050509183525050601091909101546001600160a01b0380821660208085019190915260ff600160a01b840481161515604080870191909152600160a81b90940416151560609094019390935283820151825163313ce56760e01b8152925194955060009491169263313ce56792600480820193918290030181865afa158015613e02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e269190615174565b613e3190600a61527b565b9050600085828560010154613e46919061515d565b613e50919061505e565b9050600082856002015488613e65919061515d565b613e6f919061505e565b60048601839055600586018190556002860154909150821115613f57576000856002015483613e9e9190615080565b9050600085604001516001600160a01b031663a0712d68836040518263ffffffff1660e01b8152600401613ed491815260200190565b6020604051808303816000875af1158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f17919061528a565b905080613f505760405162461bcd60e51b815260206004820152600760248201526608aa4a4beac5c760cb1b604482015260640161061d565b5050614020565b6000828660020154613f699190615080565b9050801561401e576040808601519051630852cd8d60e31b8152600481018390526000916001600160a01b0316906342966c68906024016020604051808303816000875af1158015613fbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe3919061528a565b90508061401c5760405162461bcd60e51b815260206004820152600760248201526611549497d58b8d60ca1b604482015260640161061d565b505b505b61402a8682614f65565b85600101541061416f576000868287600101546140479190615080565b6140519190615080565b905080156141695784516040516370a0823160e01b815230600482015282916001600160a01b0316906370a0823190602401602060405180830381865afa1580156140a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140c49190614fad565b10156140fd5760405162461bcd60e51b815260206004820152600860248201526722a9292fab17189960c11b604482015260640161061d565b610200850151855161411b916001600160a01b039091169083613965565b610200850151604080516001600160a01b039092168252602082018390528a9130917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a35b5061425c565b60018501546000906141818884614f65565b61418b9190615080565b85516102008701516040516370a0823160e01b81526001600160a01b03918216600482015292935083929116906370a0823190602401602060405180830381865afa1580156141de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142029190614fad565b101561423b5760405162461bcd60e51b81526020600482015260086024820152674552525f562e313360c01b604482015260640161061d565b610200850151855161425a916001600160a01b03909116903084613b6b565b505b61426588614616565b5050505050505050565b600081815260076020818152604080842060068352818520600c015485529091529091209081015460048201545b8254821080156142ae57506002545a115b15614367576000848152600b6020908152604080832060068352818420600c0154808552908352818420868552835281842054888552600a84528285206001600160a01b03909116808652908452828520918552925282205460018601549192909161431a838661515d565b614324919061505e565b9050801561435257600087815260066020526040902060020154614352906001600160a01b03168483613965565b8461435c81614f7e565b95505050505061429d565b5060079091015550565b60006143c6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661481a9092919063ffffffff16565b90508051600014806143e75750808060200190518101906143e7919061528a565b6139c85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161061d565b60008281526006602090815260408083206002810154825163313ce56760e01b815292518594929385936001600160a01b039093169263313ce567926004808401938290030181865afa1580156144a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c59190615174565b6144d090600a61527b565b905060008260020160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061454d9190614fad565b9050600093508594508583600d0154101561460c578161271082856003015486600d01548a61457c9190615080565b614586919061515d565b614590919061515d565b61459a919061505e565b6145a4919061505e565b9350831561460c578583600d01819055508383600e0160008282546145c99190614f65565b909155506000905084836145dd848a61515d565b6145e7919061505e565b6145f19190615080565b9050816145fe848361515d565b614608919061505e565b9550505b5050509250929050565b60008181526009602052604090205481906146435760405162461bcd60e51b815260040161061d90614f2d565b600061464e836117d8565b60008481526007602090815260408083208484529091529020600881015460069091015491925061467e91614f65565b42106139c85760008381526007602090815260408083208484529091529020600301546146bd5760405162461bcd60e51b815260040161061d90614fc6565b6040805161012081018252600080825260208201819052818301819052606082018190526080820181905260a082015260048054925163022684db60e41b8152908101869052909160c08301916001600160a01b03909116906322684db090602401602060405180830381865afa15801561473c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147609190614fad565b8152600060208083018290528682526006808252604080842060089081015495820195909552888452600780845281852060098086528387208054885291865283872089518155898701516001820155938901516002850155606089015160038501556080890151600485015560a0890151600585015560c08901519484019490945560e08801519183019190915561010090960151940193909355868252919091528154919061481083614f7e565b9190505550505050565b6060611844848460008585600080866001600160a01b0316858760405161484191906152cb565b60006040518083038185875af1925050503d806000811461487e576040519150601f19603f3d011682016040523d82523d6000602084013e614883565b606091505b50915091506148948783838761489f565b979650505050505050565b6060831561490e578251600003614907576001600160a01b0385163b6149075760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161061d565b5081611844565b61184483838151156149235781518083602001fd5b8060405162461bcd60e51b815260040161061d91906152e7565b828054828255906000526020600020908101928215614992579160200282015b8281111561499257825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061495d565b5061499e9291506149a2565b5090565b5b8082111561499e57600081556001016149a3565b6001600160a01b03811681146109a557600080fd5b80356149d7816149b7565b919050565b600080604083850312156149ef57600080fd5b823591506020830135614a01816149b7565b809150509250929050565b600060208284031215614a1e57600080fd5b5035919050565b60008060408385031215614a3857600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015614a805781516001600160a01b031687529582019590820190600101614a5b565b509495945050505050565b602081526000614a9e6020830184614a47565b9392505050565b60008060008060808587031215614abb57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff81118282101715614b1157614b11614ad7565b60405290565b600082601f830112614b2857600080fd5b8135602067ffffffffffffffff80831115614b4557614b45614ad7565b8260051b604051601f19603f83011681018181108482111715614b6a57614b6a614ad7565b604052938452858101830193838101925087851115614b8857600080fd5b83870191505b84821015614894578135614ba1816149b7565b83529183019190830190614b8e565b80151581146109a557600080fd5b80356149d781614bb0565b600060208284031215614bdb57600080fd5b813567ffffffffffffffff80821115614bf357600080fd5b908301906101a08286031215614c0857600080fd5b614c10614aed565b614c19836149cc565b8152614c27602084016149cc565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e0820152610100808401358183015250610120808401358183015250610140614c8e8185016149cc565b908201526101608381013583811115614ca657600080fd5b614cb288828701614b17565b8284015250506101809150614cc8828401614bbe565b91810191909152949350505050565b600080600060608486031215614cec57600080fd5b505081359360208301359350604090920135919050565b600080600060608486031215614d1857600080fd5b833592506020840135614d2a816149b7565b929592945050506040919091013590565b60008060408385031215614d4e57600080fd5b82359150602083013567ffffffffffffffff811115614d6c57600080fd5b614d7885828601614b17565b9150509250929050565b60008060408385031215614d9557600080fd5b823591506020830135614a0181614bb0565b60208152614dc16020820183516001600160a01b03169052565b60006020830151614ddd60408401826001600160a01b03169052565b5060408301516001600160a01b038116606084015250606083015160808381019190915283015160a08084019190915283015160c08084019190915283015160e08084019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a0808401919091528301516101c0808401919091528301516101e080840191909152830151610260610200808501829052614eaa610280860184614a47565b90860151909250610220614ec8868201836001600160a01b03169052565b8601519050610240614edd8682018315159052565b90950151151593019290925250919050565b600060208284031215614f0157600080fd5b8135614a9e816149b7565b6020808252600790820152664552525f562e3160c81b604082015260600190565b60208082526008908201526704552525f562e31360c41b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115614f7857614f78614f4f565b92915050565b600060018201614f9057614f90614f4f565b5060010190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614fbf57600080fd5b5051919050565b6020808252600890820152674552525f562e333760c01b604082015260600190565b600060208284031215614ffa57600080fd5b8151614a9e816149b7565b60006101008a8352896020840152881515604084015280606084015261502d81840189614a47565b6001600160a01b0397881660808501529590961660a08301525060c081019290925260e09091015295945050505050565b60008261507b57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115614f7857614f78614f4f565b60208082526008908201526704552525f562e32360c41b604082015260600190565b6000816150c4576150c4614f4f565b506000190190565b60208082526008908201526708aa4a4beac5c62760c31b604082015260600190565b60006060820185835260206060818501528186548084526080860191508760005282600020935060005b8181101561513d5784546001600160a01b031683526001948501949284019201615118565b505084810360408601526151518187614a47565b98975050505050505050565b8082028115828204841417614f7857614f78614f4f565b60006020828403121561518657600080fd5b815160ff81168114614a9e57600080fd5b600181815b808511156151d25781600019048211156151b8576151b8614f4f565b808516156151c557918102915b93841c939080029061519c565b509250929050565b6000826151e957506001614f78565b816151f657506000614f78565b816001811461520c576002811461521657615232565b6001915050614f78565b60ff84111561522757615227614f4f565b50506001821b614f78565b5060208310610133831016604e8410600b8410161715615255575081810a614f78565b61525f8383615197565b806000190482111561527357615273614f4f565b029392505050565b6000614a9e60ff8416836151da565b60006020828403121561529c57600080fd5b8151614a9e81614bb0565b60005b838110156152c25781810151838201526020016152aa565b50506000910152565b600082516152dd8184602087016152a7565b9190910192915050565b60208152600082518060208401526153068160408501602087016152a7565b601f01601f1916919091016040019291505056fea26469706673582212206a672514675c083a61390eae01e0e3fa1d7ade8ebc48d43175dffde3fa34334364736f6c6343000812003360806040523480156200001157600080fd5b5060405162003a4a38038062003a4a83398101604081905262000034916200005f565b6001600081905580546001600160a01b0319166001600160a01b039290921691909117905562000091565b6000602082840312156200007257600080fd5b81516001600160a01b03811681146200008a57600080fd5b9392505050565b6139a980620000a16000396000f3fe60806040523480156200001157600080fd5b50600436106200015d5760003560e01c806372ba257011620000c7578063c74c0fac1162000086578063c74c0fac14620003b8578063ddaf8d0714620003d4578063de0ce17d14620003eb578063e1048e7414620003f4578063e8e66ab91462000420578063fd87a8ca146200043757600080fd5b806372ba257014620003145780637fb917e1146200036857806399166095146200037f578063a616f3451462000396578063b4d1d79514620003ad57600080fd5b80632fb565e811620001205780632fb565e8146200021857806337ddb624146200022f578063487caabc14620002a55780635272cd9014620002bc5780635cf4ee9114620002d05780635dc50a2114620002e757600080fd5b8063040141e5146200016257806309bb22b6146200019b57806322684db014620001c1578063282570f014620001d85780632d73c94714620001f1575b600080fd5b6200017e73c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b0390911681526020015b60405180910390f35b620001b2620001ac36600462002c99565b6200044e565b60405190815260200162000192565b620001b2620001d236600462002cbc565b62000808565b620001ef620001e936600462002c99565b62000887565b005b620002086200020236600462002cbc565b620008f8565b6040516200019292919062002cfc565b620001ef6200022936600462002c99565b62000a50565b620002466200024036600462002c99565b62000bc0565b604080516001600160a01b03998a168152602081019890985287019590955292516001600160e01b0390811660608701529151909116608085015263ffffffff1660a0840152831660c083015290911660e08201526101000162000192565b620001ef620002b636600462002d52565b62000c60565b6001546200017e906001600160a01b031681565b620001b2620002e136600462002c99565b62000f2d565b620002fe620002f836600462002d99565b62001200565b6040805192835260208301919091520162000192565b6200032b6200032536600462002dc6565b62001416565b604080519687526020870195909552938501929092526001600160a01b03908116606085015290811660808401521660a082015260c00162000192565b620001b26200037936600462002dc6565b620016f0565b620001b26200039036600462002dc6565b62001918565b620001ef620003a736600462002cbc565b62001b1c565b620001b26201518081565b6200017e735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b620001ef620003e536600462002c99565b62001b5b565b6200017e600081565b6200017e6200040536600462002cbc565b6003602052600090815260409020546001600160a01b031681565b620001b26200043136600462002c99565b62001c05565b620001b26200044836600462002dc6565b62001d19565b60015460405163db089e7960e01b81526004810184905260009182916001600160a01b039091169063db089e7990602401600060405180830381865afa1580156200049d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620004c7919081019062002f4e565b9050600060026000868152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b82821015620005b957600084815260209081902060408051610100810182526007860290920180546001600160a01b039081168452600180830154858701526002830154858501528351808701855260038401546001600160e01b0390811682526060870191909152845180880190955260048401541684526080850193909352600582015463ffffffff811660a08601526401000000009004811660c08501526006909101541660e08301529083529092019101620004fe565b5050505090508051600103620006945780600081518110620005df57620005df620030c2565b602002602001015160c001516001600160a01b031682602001516001600160a01b0316036200065a5762000649620006428583600081518110620006275762000627620030c2565b60200260200101516060015162001f7390919063ffffffff16565b5160701c90565b6001600160901b0316925062000800565b62000649620006428583600081518110620006795762000679620030c2565b60200260200101516080015162001f7390919063ffffffff16565b60408051602081019091526000815281600081518110620006b957620006b9620030c2565b602002602001015160c001516001600160a01b031683600001516001600160a01b0316036200070c5781600081518110620006f857620006f8620030c2565b602002602001015160800151905062000731565b81600081518110620007225762000722620030c2565b60200260200101516060015190505b81600181518110620007475762000747620030c2565b602002602001015160c001516001600160a01b031683602001516001600160a01b031603620007b057620007a8620007a0836001815181106200078e576200078e620030c2565b60200260200101516080015162002018565b82906200212d565b9050620007e3565b620007e0620007a083600181518110620007ce57620007ce620030c2565b60200260200101516060015162002018565b90505b620007f362000642828762001f73565b6001600160901b03169350505b505092915050565b6000818152600360209081526040808320548151630430a36960e11b815291516001600160a01b039091169263086146d292600480820193918290030181865afa1580156200085b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008819190620030d8565b92915050565b6000828152600360205260409081902054905163180126ff60e11b8152600481018390526001600160a01b03909116906330024dfe90602401600060405180830381600087803b158015620008db57600080fd5b505af1158015620008f0573d6000803e3d6000fd5b505050505050565b60015460405163db089e7960e01b81526004810183905260609160009182916001600160a01b03169063db089e7990602401600060405180830381865afa15801562000948573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000972919081019062002f4e565b602001519050806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620009b7573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620009e19190810190620030f2565b9250806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000a22573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a489190620030d8565b915050915091565b600082815260026020526040812080548390811062000a735762000a73620030c2565b60009182526020822060079091020180549092508190819062000a9f906001600160a01b031662002342565b6005870154929550909350915060009062000ac19063ffffffff1683620031a7565b9050620151808163ffffffff16101562000ade5750505050505050565b60405180602001604052808263ffffffff1687600101548762000b029190620031ce565b62000b0e9190620031fa565b6001600160e01b0390811690915290516003870180546001600160e01b031916919092161790556001850184905560408051602081019091526002860154819063ffffffff84169062000b629087620031ce565b62000b6e9190620031fa565b6001600160e01b0390811690915290516004870180546001600160e01b031916919092161790555060028401919091556005909201805463ffffffff191663ffffffff90931692909217909155505050565b6002602052816000526040600020818154811062000bdd57600080fd5b600091825260209182902060079091020180546001820154600283015460408051808701825260038601546001600160e01b03908116825282519788019092526004860154909116865260058501546006909501546001600160a01b03948516985092965090949093909263ffffffff8216926401000000009092048116911688565b62000c6a62002553565b6001546001600160a01b0316331462000cb55760405162461bcd60e51b81526020600482015260086024820152674552525f56472e3160c01b60448201526064015b60405180910390fd5b60405163e6a4390560e01b81526001600160a01b03808316600483015283166024820152735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f90600090829063e6a4390590604401602060405180830381865afa15801562000d1b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000d41919062003211565b90506001600160a01b03811662000f0c5760405163e6a4390560e01b81526001600160a01b03848116600483015273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2602483015283169063e6a4390590604401602060405180830381865afa15801562000db3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000dd9919062003211565b90506001600160a01b03811662000e1e5760405162461bcd60e51b815260206004820152600860248201526722a9292fab23971960c11b604482015260640162000cac565b8062000e2b8682620025ae565b60405163e6a4390560e01b81526001600160a01b03868116600483015273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2602483015284169063e6a4390590604401602060405180830381865afa15801562000e8c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000eb2919062003211565b91506001600160a01b03821662000ef75760405162461bcd60e51b81526020600482015260086024820152674552525f56472e3360c01b604482015260640162000cac565b8162000f048782620025ae565b505062000f1b565b8062000f198682620025ae565b505b505062000f286001600055565b505050565b60015460405163db089e7960e01b81526004810184905260009182916001600160a01b039091169063db089e7990602401600060405180830381865afa15801562000f7c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000fa6919081019062002f4e565b9050600060026000868152602001908152602001600020805480602002602001604051908101604052809291908181526020016000905b828210156200109857600084815260209081902060408051610100810182526007860290920180546001600160a01b039081168452600180830154858701526002830154858501528351808701855260038401546001600160e01b0390811682526060870191909152845180880190955260048401541684526080850193909352600582015463ffffffff811660a08601526401000000009004811660c08501526006909101541660e0830152908352909201910162000fdd565b5050505090508051600103620011065780600081518110620010be57620010be620030c2565b602002602001015160c001516001600160a01b031682600001516001600160a01b0316036200065a5762000649620006428583600081518110620006275762000627620030c2565b604080516020810190915260008152816000815181106200112b576200112b620030c2565b602002602001015160c001516001600160a01b031683602001516001600160a01b0316036200117e57816000815181106200116a576200116a620030c2565b6020026020010151608001519050620011a3565b81600081518110620011945762001194620030c2565b60200260200101516060015190505b81600181518110620011b957620011b9620030c2565b602002602001015160c001516001600160a01b031683600001516001600160a01b031603620007b057620007a8620007a0836001815181106200078e576200078e620030c2565b60015460405163ae51accb60e01b81526004810185905260248101839052600091829182916001600160a01b03169063ae51accb9060440161012060405180830381865afa15801562001257573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200127d919062003231565b60015460405163db089e7960e01b8152600481018990529192506000916001600160a01b039091169063db089e7990602401600060405180830381865afa158015620012cd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620012f7919081019062002f4e565b90508161010001518260c00151620013109190620032af565b4210156200134c5760405162461bcd60e51b815260206004820152600860248201526711549497d591cb8d60c21b604482015260640162000cac565b6000826040015187620013609190620032c5565b9050600082604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620013a7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620013cd9190620032df565b60ff1690506000620013e182600a62003401565b9050600089828760200151620013f89190620032c5565b620014049190620031fa565b939b939a509298505050505050505050565b60015460405163db089e7960e01b815260048101849052600091829182918291829182916001600160a01b039091169063db089e7990602401600060405180830381865afa1580156200146d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001497919081019062002f4e565b602001516040516370a0823160e01b81526001600160a01b03898116600483015291945084918216906370a0823190602401602060405180830381865afa158015620014e7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200150d9190620030d8565b60015460405163db089e7960e01b8152600481018c90529198506001600160a01b03169063db089e7990602401600060405180830381865afa15801562001558573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001582919081019062002f4e565b60409081015190516370a0823160e01b81526001600160a01b038a8116600483015291945084918216906370a0823190602401602060405180830381865afa158015620015d3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015f99190620030d8565b60015460405163db089e7960e01b8152600481018d90529198506001600160a01b03169063db089e7990602401600060405180830381865afa15801562001644573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200166e919081019062002f4e565b516040516370a0823160e01b81526001600160a01b038b8116600483015291945084918216906370a0823190602401602060405180830381865afa158015620016bb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620016e19190620030d8565b96505050509295509295509295565b600154604051631069f3b560e01b8152600481018490526001600160a01b0383811660248301526000928392911690631069f3b590604401606060405180830381865afa15801562001746573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200176c91906200340f565b51905080620017a95760405162461bcd60e51b81526020600482015260086024820152674552525f56472e3560c01b604482015260640162000cac565b60015460405163ae51accb60e01b815260048101869052602481018390526000916001600160a01b03169063ae51accb9060440161012060405180830381865afa158015620017fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001822919062003231565b90506000816060015111620018655760405162461bcd60e51b815260206004820152600860248201526722a9292fab23971b60c11b604482015260640162000cac565b6001546040516395ba658560e01b8152600481018790526001600160a01b0386811660248301526044820185905260009216906395ba65859060640160a060405180830381865afa158015620018bf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620018e591906200346f565b60200151905081604001518260a0015182620019029190620032c5565b6200190e9190620031fa565b9695505050505050565b60015460405163db089e7960e01b81526004810184905260009182916001600160a01b039091169063db089e7990602401600060405180830381865afa15801562001967573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001991919081019062002f4e565b6020015160015460405163db089e7960e01b8152600481018790529192506001600160a01b03169063db089e7990602401600060405180830381865afa158015620019e0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001a0a919081019062002f4e565b60800151600160009054906101000a90046001600160a01b03166001600160a01b03166395e911a86040518163ffffffff1660e01b8152600401602060405180830381865afa15801562001a62573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001a889190620030d8565b6040516370a0823160e01b81526001600160a01b03868116600483015262001afc9188918616906370a0823190602401602060405180830381865afa15801562001ad6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001ac9190620030d8565b62001b089190620032c5565b62001b149190620031fa565b949350505050565b60005b60008281526002602052604090205481101562001b575762001b42828262000a50565b8062001b4e81620034e9565b91505062001b1f565b5050565b6001546001600160a01b0316331462001ba25760405162461bcd60e51b81526020600482015260086024820152674552525f56472e3160c01b604482015260640162000cac565b8060405162001bb19062002c8b565b908152602001604051809103906000f08015801562001bd4573d6000803e3d6000fd5b5060009283526003602052604090922080546001600160a01b0319166001600160a01b039093169290921790915550565b600154604080516312bd223560e31b815290516000926001600160a01b0316916395e911a89160048083019260209291908290030181865afa15801562001c50573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001c769190620030d8565b60015460405163db089e7960e01b8152600481018690526001600160a01b039091169063db089e7990602401600060405180830381865afa15801562001cc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001cea919081019062002f4e565b6080015162001cfa858562000f2d565b62001d069190620032c5565b62001d129190620031fa565b9392505050565b60015460405163db089e7960e01b81526004810184905260009182916001600160a01b039091169063db089e7990602401600060405180830381865afa15801562001d68573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001d92919081019062002f4e565b600154604051631069f3b560e01b8152600481018790526001600160a01b03868116602483015292935060009290911690631069f3b590604401606060405180830381865afa15801562001dea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001e1091906200340f565b60408101516020820151919250906000905b8281101562001f6857610120850151600154604051631d069dbb60e31b8152600481018b90526001600160a01b038a81166024830152604482018590529091169063e834edd8906064016040805180830381865afa15801562001e89573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001eaf919062003505565b5162001ebc9190620032af565b421062001f6857600154604051631d069dbb60e31b8152600481018a90526001600160a01b038981166024830152604482018490529091169063e834edd8906064016040805180830381865afa15801562001f1b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001f41919062003505565b6020015162001f519083620032af565b91508062001f5f81620034e9565b91505062001e22565b509695505050505050565b604080516020810190915260008152600082158062001fb5575083516001600160e01b03168362001fa58183620032c5565b925062001fb39083620031fa565b145b620020035760405162461bcd60e51b815260206004820152601960248201527f4669786564506f696e743a3a6d756c3a206f766572666c6f7700000000000000604482015260640162000cac565b60408051602081019091529081529392505050565b60408051602081019091526000815281516001600160e01b0316600003620020965760405162461bcd60e51b815260206004820152602a60248201527f4669786564506f696e743a3a7265636970726f63616c3a207265636970726f63604482015269616c206f66207a65726f60b01b606482015260840162000cac565b81516001600160e01b0316600103620020f25760405162461bcd60e51b815260206004820181905260248201527f4669786564506f696e743a3a7265636970726f63616c3a206f766572666c6f77604482015260640162000cac565b604051806020016040528083600001516001600160e01b0316600160e01b6200211c9190620031fa565b6001600160e01b0316905292915050565b60408051602081019091526000815282516001600160e01b031615806200215c575081516001600160e01b0316155b1562002178575060408051602081019091526000815262000881565b825182516001600160701b03607083811c8216938216929081901c821691166000620021a5838662003558565b90506000620021c16001600160701b0380851690871662003558565b90506000620021dd6001600160701b0380861690891662003558565b90506000620021f96001600160701b0380891690881662003558565b90506001600160701b036001600160e01b0385161115620022675760405162461bcd60e51b815260206004820152602160248201527f4669786564506f696e743a3a6d756c75713a207570706572206f766572666c6f6044820152607760f81b606482015260840162000cac565b6000607084811c6001600160701b0316906001600160e01b0384811691620022a89187169089901b6dffffffffffffffffffffffffffff60701b16620032af565b620022b49190620032af565b620022c09190620032af565b90506001600160e01b038111156200231b5760405162461bcd60e51b815260206004820152601f60248201527f4669786564506f696e743a3a6d756c75713a2073756d206f766572666c6f7700604482015260640162000cac565b60408051602081019091526001600160e01b0390911681529b9a5050505050505050505050565b60008060006200235162002991565b9050836001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002392573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023b89190620030d8565b9250836001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa158015620023f9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200241f9190620030d8565b91506000806000866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562002465573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200248b9190620035a5565b9250925092508363ffffffff168163ffffffff161462002549576000620024b38286620031a7565b90508063ffffffff16620024da846001600160701b0316866001600160701b0316620029a9565b51620024f091906001600160e01b0316620032c5565b620024fc9088620032af565b96508063ffffffff1662002523856001600160701b0316856001600160701b0316620029a9565b516200253991906001600160e01b0316620032c5565b620025459087620032af565b9550505b5050509193909250565b600260005403620025a75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640162000cac565b6002600055565b6000816001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015620025ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620026159190620035a5565b925050506000806000620026298562002342565b9194509250905060006200263e8583620031a7565b9050600060405180602001604052808363ffffffff16896001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002693573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620026b99190620030d8565b620026c59089620031ce565b620026d19190620031fa565b6001600160e01b03168152509050600060405180602001604052808463ffffffff168a6001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002732573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620027589190620030d8565b620027649089620031ce565b620027709190620031fa565b6001600160e01b03168152509050600260008a81526020019081526020016000206040518061010001604052808a6001600160a01b031681526020018881526020018781526020018481526020018381526020018663ffffffff1681526020018a6001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200280f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002835919062003211565b6001600160a01b031681526020018a6001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002882573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620028a8919062003211565b6001600160a01b039081169091528254600181810185556000948552602094859020845160079093020180549284166001600160a01b03199384161781559484015190850155604083015160028501556060830151516003850180546001600160e01b039283166001600160e01b03199182161790915560808501515160048701805491909316911617905560a083015160058501805460c08601518516640100000000026001600160c01b031990911663ffffffff9093169290921791909117905560e090920151600690930180549390911692909116919091179055505050505050505050565b6000620029a464010000000042620035f0565b905090565b6040805160208101909152600081526000821162002a195760405162461bcd60e51b815260206004820152602660248201527f4669786564506f696e743a3a6672616374696f6e3a206469766973696f6e206260448201526579207a65726f60d01b606482015260840162000cac565b8260000362002a38575060408051602081019091526000815262000881565b6001600160901b03831162002ad557600062002a5983607086901b620031fa565b90506001600160e01b0381111562002ab45760405162461bcd60e51b815260206004820152601e60248201527f4669786564506f696e743a3a6672616374696f6e3a206f766572666c6f770000604482015260640162000cac565b6040518060200160405280826001600160e01b031681525091505062000881565b600062002a5984600160701b85600080806000198587098587029250828110838203039150508060000362002b1e576000841162002b1257600080fd5b50829004905062001d12565b80841162002b2b57600080fd5b600084868809808403938111909203919050600062002b4d86196001620032af565b861695869004959384900493600081900304600101905062002b708184620032c5565b90931792600062002b83876003620032c5565b600218905062002b948188620032c5565b62002ba1906002620031ce565b62002bad9082620032c5565b905062002bbb8188620032c5565b62002bc8906002620031ce565b62002bd49082620032c5565b905062002be28188620032c5565b62002bef906002620031ce565b62002bfb9082620032c5565b905062002c098188620032c5565b62002c16906002620031ce565b62002c229082620032c5565b905062002c308188620032c5565b62002c3d906002620031ce565b62002c499082620032c5565b905062002c578188620032c5565b62002c64906002620031ce565b62002c709082620032c5565b905062002c7e8186620032c5565b9998505050505050505050565b61036c806200360883390190565b6000806040838503121562002cad57600080fd5b50508035926020909101359150565b60006020828403121562002ccf57600080fd5b5035919050565b60005b8381101562002cf357818101518382015260200162002cd9565b50506000910152565b604081526000835180604084015262002d1d81606085016020880162002cd6565b602083019390935250601f91909101601f191601606001919050565b6001600160a01b038116811462002d4f57600080fd5b50565b60008060006060848603121562002d6857600080fd5b83359250602084013562002d7c8162002d39565b9150604084013562002d8e8162002d39565b809150509250925092565b60008060006060848603121562002daf57600080fd5b505081359360208301359350604090920135919050565b6000806040838503121562002dda57600080fd5b82359150602083013562002dee8162002d39565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051610260810167ffffffffffffffff8111828210171562002e365762002e3662002df9565b60405290565b604051610120810167ffffffffffffffff8111828210171562002e365762002e3662002df9565b604051601f8201601f1916810167ffffffffffffffff8111828210171562002e8f5762002e8f62002df9565b604052919050565b805162002ea48162002d39565b919050565b600082601f83011262002ebb57600080fd5b8151602067ffffffffffffffff82111562002eda5762002eda62002df9565b8160051b62002eeb82820162002e63565b928352848101820192828101908785111562002f0657600080fd5b83870192505b8483101562002f3257825162002f228162002d39565b8252918301919083019062002f0c565b979650505050505050565b8051801515811462002ea457600080fd5b60006020828403121562002f6157600080fd5b815167ffffffffffffffff8082111562002f7a57600080fd5b90830190610260828603121562002f9057600080fd5b62002f9a62002e0f565b62002fa58362002e97565b815262002fb56020840162002e97565b602082015262002fc86040840162002e97565b6040820152606083810151908201526080808401519082015260a0808401519082015260c0808401519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401519082015261018080840151908201526101a080840151908201526101c080840151908201526101e080840151838111156200306157600080fd5b6200306f8882870162002ea9565b82840152505061020091506200308782840162002e97565b8282015261022091506200309d82840162002f3d565b828201526102409150620030b382840162002f3d565b91810191909152949350505050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215620030eb57600080fd5b5051919050565b6000602082840312156200310557600080fd5b815167ffffffffffffffff808211156200311e57600080fd5b818401915084601f8301126200313357600080fd5b81518181111562003148576200314862002df9565b6200315d601f8201601f191660200162002e63565b91508082528560208285010111156200317557600080fd5b6200318881602084016020860162002cd6565b50949350505050565b634e487b7160e01b600052601160045260246000fd5b63ffffffff828116828216039080821115620031c757620031c762003191565b5092915050565b8181038181111562000881576200088162003191565b634e487b7160e01b600052601260045260246000fd5b6000826200320c576200320c620031e4565b500490565b6000602082840312156200322457600080fd5b815162001d128162002d39565b600061012082840312156200324557600080fd5b6200324f62002e3c565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b8082018082111562000881576200088162003191565b808202811582820484141762000881576200088162003191565b600060208284031215620032f257600080fd5b815160ff8116811462001d1257600080fd5b600181815b808511156200334557816000190482111562003329576200332962003191565b808516156200333757918102915b93841c939080029062003309565b509250929050565b6000826200335e5750600162000881565b816200336d5750600062000881565b81600181146200338657600281146200339157620033b1565b600191505062000881565b60ff841115620033a557620033a562003191565b50506001821b62000881565b5060208310610133831016604e8410600b8410161715620033d6575081810a62000881565b620033e2838362003304565b8060001904821115620033f957620033f962003191565b029392505050565b600062001d1283836200334d565b6000606082840312156200342257600080fd5b6040516060810181811067ffffffffffffffff8211171562003448576200344862002df9565b80604052508251815260208301516020820152604083015160408201528091505092915050565b600060a082840312156200348257600080fd5b60405160a0810181811067ffffffffffffffff82111715620034a857620034a862002df9565b806040525082518152602083015160208201526040830151604082015260608301516060820152620034dd6080840162002f3d565b60808201529392505050565b600060018201620034fe57620034fe62003191565b5060010190565b6000604082840312156200351857600080fd5b6040516040810181811067ffffffffffffffff821117156200353e576200353e62002df9565b604052825181526020928301519281019290925250919050565b6001600160e01b0382811682821681810283169291811582850482141762003584576200358462003191565b50505092915050565b80516001600160701b038116811462002ea457600080fd5b600080600060608486031215620035bb57600080fd5b620035c6846200358d565b9250620035d6602085016200358d565b9150604084015163ffffffff8116811462002d8e57600080fd5b600082620036025762003602620031e4565b50069056fe608060405234801561001057600080fd5b5060405161036c38038061036c83398101604081905261002f9161004d565b600080546001600160a01b0319163317905542600155600255610066565b60006020828403121561005f57600080fd5b5051919050565b6102f7806100756000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80630604061814610067578063086146d21461008357806330024dfe1461008b5780634ff0876a146100a057806378e97925146100a95780638da5cb5b146100b2575b600080fd5b61007060035481565b6040519081526020015b60405180910390f35b6100706100dd565b61009e61009936600461022d565b610182565b005b61007060025481565b61007060015481565b6000546100c5906001600160a01b031681565b6040516001600160a01b03909116815260200161007a565b60006001544210156101425760405162461bcd60e51b815260206004820152602360248201527f54696d654f7261636c653a205175657279206265666f72652073746172742074604482015262696d6560e81b60648201526084015b60405180910390fd5b600060025460015442610155919061025c565b61015f9190610275565b90506002548161016f9190610297565b60015461017c91906102ae565b91505090565b6000546001600160a01b031633146101f45760405162461bcd60e51b815260206004820152602f60248201527f54696d654f7261636c653a204f6e6c79206f776e65722063616e206368616e6760448201526e329032b837b1b4223ab930ba34b7b760891b6064820152608401610139565b600254600154610204904261025c565b61020e9190610275565b6003600082825461021f91906102ae565b909155505042600155600255565b60006020828403121561023f57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561026f5761026f610246565b92915050565b60008261029257634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761026f5761026f610246565b8082018082111561026f5761026f61024656fea26469706673582212209cb6e62a50fbd0064d00243119df94ed5dd9349507d772c169d1913ebd0014b464736f6c63430008120033a2646970667358221220708089fedc90033f80240895bf513413251cf8ed550f4ca49df7aa095589e91364736f6c63430008120033608060405234801561001057600080fd5b50611013806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80636621387d14610030575b600080fd5b610038610054565b6040516001600160a01b03909116815260200160405180910390f35b6000803360405161006490610097565b6001600160a01b039091168152602001604051809103906000f080158015610090573d6000803e3d6000fd5b5092915050565b610f39806100a58339019056fe60806040523480156200001157600080fd5b5060405162000f3938038062000f3983398101604081905262000034916200011b565b6040518060400160405280600c81526020016b43495646756e64536861726560a01b815250604051806040016040528060048152602001632c21a4ab60e11b8152508160039081620000879190620001f2565b506004620000968282620001f2565b505050620000b3620000ad620000c560201b60201c565b620000c9565b620000be81620000c9565b50620002be565b3390565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6000602082840312156200012e57600080fd5b81516001600160a01b03811681146200014657600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200017857607f821691505b6020821081036200019957634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001ed57600081815260208120601f850160051c81016020861015620001c85750805b601f850160051c820191505b81811015620001e957828155600101620001d4565b5050505b505050565b81516001600160401b038111156200020e576200020e6200014d565b62000226816200021f845462000163565b846200019f565b602080601f8311600181146200025e5760008415620002455750858301515b600019600386901b1c1916600185901b178555620001e9565b600085815260208120601f198616915b828110156200028f578886015182559484019460019091019084016200026e565b5085821015620002ae5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b610c6b80620002ce6000396000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063715018a611610097578063a457c2d711610066578063a457c2d714610209578063a9059cbb1461021c578063dd62ed3e1461022f578063f2fde38b1461024257600080fd5b8063715018a6146101c95780638da5cb5b146101d357806395d89b41146101ee578063a0712d68146101f657600080fd5b8063313ce567116100d3578063313ce5671461016b578063395093511461017a57806342966c681461018d57806370a08231146101a057600080fd5b806306fdde0314610105578063095ea7b31461012357806318160ddd1461014657806323b872dd14610158575b600080fd5b61010d610255565b60405161011a9190610aa1565b60405180910390f35b610136610131366004610b06565b6102e7565b604051901515815260200161011a565b6002545b60405190815260200161011a565b610136610166366004610b30565b610301565b6040516012815260200161011a565b610136610188366004610b06565b610325565b61013661019b366004610b6c565b610347565b61014a6101ae366004610b85565b6001600160a01b031660009081526020819052604090205490565b6101d161035b565b005b6005546040516001600160a01b03909116815260200161011a565b61010d61036f565b610136610204366004610b6c565b61037e565b610136610217366004610b06565b610397565b61013661022a366004610b06565b610417565b61014a61023d366004610ba7565b610425565b6101d1610250366004610b85565b610450565b60606003805461026490610bda565b80601f016020809104026020016040519081016040528092919081815260200182805461029090610bda565b80156102dd5780601f106102b2576101008083540402835291602001916102dd565b820191906000526020600020905b8154815290600101906020018083116102c057829003601f168201915b5050505050905090565b6000336102f58185856104c9565b60019150505b92915050565b60003361030f8582856105ee565b61031a858585610668565b506001949350505050565b6000336102f58185856103388383610425565b6103429190610c14565b6104c9565b6000610353338361080c565b506001919050565b610363610936565b61036d6000610990565b565b60606004805461026490610bda565b6000610388610936565b61035333836109e2565b919050565b600033816103a58286610425565b90508381101561040a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b61031a82868684036104c9565b6000336102f5818585610668565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b610458610936565b6001600160a01b0381166104bd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610401565b6104c681610990565b50565b6001600160a01b03831661052b5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610401565b6001600160a01b03821661058c5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610401565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006105fa8484610425565b9050600019811461066257818110156106555760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610401565b61066284848484036104c9565b50505050565b6001600160a01b0383166106cc5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610401565b6001600160a01b03821661072e5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610401565b6001600160a01b038316600090815260208190526040902054818110156107a65760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610401565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610662565b6001600160a01b03821661086c5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610401565b6001600160a01b038216600090815260208190526040902054818110156108e05760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610401565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016105e1565b6005546001600160a01b0316331461036d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610401565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038216610a385760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610401565b8060026000828254610a4a9190610c14565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b81811015610ace57858101830151858201604001528201610ab2565b506000604082860101526040601f19601f8301168501019250505092915050565b80356001600160a01b038116811461039257600080fd5b60008060408385031215610b1957600080fd5b610b2283610aef565b946020939093013593505050565b600080600060608486031215610b4557600080fd5b610b4e84610aef565b9250610b5c60208501610aef565b9150604084013590509250925092565b600060208284031215610b7e57600080fd5b5035919050565b600060208284031215610b9757600080fd5b610ba082610aef565b9392505050565b60008060408385031215610bba57600080fd5b610bc383610aef565b9150610bd160208401610aef565b90509250929050565b600181811c90821680610bee57607f821691505b602082108103610c0e57634e487b7160e01b600052602260045260246000fd5b50919050565b808201808211156102fb57634e487b7160e01b600052601160045260246000fdfea2646970667358221220113f07050d92b4e17432a4833db52fe7ef02426722ac29b5d00ec28302b6a5e364736f6c63430008120033a264697066735822122032af93e6de8e7306be1210a297287d4c16b94ecb1ad5d7e82adcf1970680275c64736f6c63430008120033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061021c5760003560e01c806395ba658511610125578063d8808306116100ad578063e834edd81161007c578063e834edd81461055d578063f2fde38b1461058b578063f41fc3091461059e578063f4f3b200146105b1578063fc5358e8146105c457600080fd5b8063d880830614610504578063daff97b514610517578063db089e791461052a578063e2bbb1581461054a57600080fd5b80639f01f7ba116100f45780639f01f7ba14610442578063ae51accb14610455578063b0b1f9e9146104d5578063c602e48e146104e8578063c6a1c131146104f157600080fd5b806395ba6585146103bc57806395e911a81461041357806396bda2841461041c57806398f3fc571461042f57600080fd5b80634aad6b22116101a857806372fada5c1161017757806372fada5c1461035f5780637fae6d4d14610372578063813e6241146103855780638550c908146103985780638da5cb5b146103ab57600080fd5b80634aad6b221461031e5780635b65b9ab146103315780635d7035c614610344578063715018a61461035757600080fd5b80633fdefa6e116101ef5780633fdefa6e146102ae578063404f4e0d146102c5578063441a3e70146102e557806345a7f794146102f8578063481c1d8e1461030b57600080fd5b80631069f3b514610221578063179aa0401461025b5780631aa277a514610270578063282570f01461029b575b600080fd5b61023461022f3660046149dc565b6105d7565b60408051825181526020808401519082015291810151908201526060015b60405180910390f35b61026e610269366004614a0c565b610670565b005b600454610283906001600160a01b031681565b6040516001600160a01b039091168152602001610252565b61026e6102a9366004614a25565b6109a8565b6102b760025481565b604051908152602001610252565b6102d86102d3366004614a25565b610a9d565b6040516102529190614a8b565b61026e6102f3366004614a25565b610bb7565b61026e610306366004614aa5565b610e51565b61026e610319366004614bc9565b610f1d565b61026e61032c366004614a0c565b61146a565b61026e61033f366004614cd7565b611729565b6102b7610352366004614a0c565b6117d8565b61026e61184c565b61026e61036d366004614a0c565b611860565b61026e610380366004614a0c565b611cb5565b61026e6103933660046149dc565b611d4c565b61026e6103a6366004614a25565b611e5a565b6000546001600160a01b0316610283565b6103cf6103ca366004614d03565b6121bd565b6040516102529190600060a0820190508251825260208301516020830152604083015160408301526060830151606083015260808301511515608083015292915050565b6102b761271081565b61026e61042a366004614a0c565b612282565b600554610283906001600160a01b031681565b61026e610450366004614a0c565b6124de565b610468610463366004614a25565b6126dc565b6040516102529190600061012082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b61026e6104e3366004614a0c565b6127fa565b6102b760035481565b61026e6104ff366004614d3b565b612aa6565b61026e610512366004614a0c565b612c4f565b61026e610525366004614d82565b612dd4565b61053d610538366004614a0c565b612e67565b6040516102529190614da7565b61026e610558366004614a25565b6130a3565b61057061056b366004614d03565b613597565b60408051825181526020928301519281019290925201610252565b61026e610599366004614eef565b613617565b61026e6105ac366004614a0c565b61368d565b61026e6105bf366004614eef565b6136d6565b61026e6105d2366004614cd7565b613826565b6105fb60405180606001604052806000815260200160008152602001600081525090565b8280600354116106265760405162461bcd60e51b815260040161061d90614f0c565b60405180910390fd5b505060009182526008602090815260408084206001600160a01b03909316845291815291819020815160608101835281548152600182015493810193909352600201549082015290565b61067861390c565b80806003541161069a5760405162461bcd60e51b815260040161061d90614f0c565b60008281526009602052604090205482906106c75760405162461bcd60e51b815260040161061d90614f2d565b600083815260066020818152604080842081516102608101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a08201529381015460c0850152600781015460e085015260088101546101008501526009810154610120850152600a810154610140850152600b810154610160850152600c810154610180850152600d8101546101a0850152600e8101546101c0850152600f8101805483518186028101860190945280845291936101e086019392908301828280156107db57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107bd575b5050509183525050601091909101546001600160a01b03811660208084019190915260ff600160a01b830481161515604080860191909152600160a81b909304161515606090930192909252600087815260089092528120919250908161083f3390565b6001600160a01b03168152602081019190915260400160009081206002810154600182015491935091815b838110156108fa5761012086015160008a8152600c6020908152604080832033845282528083208584529091529020546108a49190614f65565b42106108fa576000898152600c6020908152604080832033845282528083208484529091529020600101546108d99083614f65565b91506108e6816001614f65565b9250806108f281614f7e565b91505061086a565b50600081116109365760405162461bcd60e51b81526020600482015260086024820152674552525f562e313960c01b604482015260640161061d565b600184018290556109563360208701516001600160a01b03169083613965565b6040805189815233602082015280820183905290517ffccb8ae12beda66b6d00eeb9e618561189d5f249c36ccad81909d3bb554d58db9181900360600190a1505050505050506109a560018055565b50565b6109b06139cd565b8180600354116109d25760405162461bcd60e51b815260040161061d90614f0c565b600083815260066020908152604091829020600801548251868152918201529081018390527fc8cebf046c3a3799bf1206980180c44983f298221ad03c0fe827ab5c5c0a398c9060600160405180910390a160048054604051630282570f60e41b8152918201859052602482018490526001600160a01b03169063282570f090604401600060405180830381600087803b158015610a6f57600080fd5b505af1158015610a83573d6000803e3d6000fd5b505050600093845250506006602052604090912060080155565b6060828060035411610ac15760405162461bcd60e51b815260040161061d90614f0c565b600084815260076020908152604080832086845290915290205467ffffffffffffffff811115610af357610af3614ad7565b604051908082528060200260200182016040528015610b1c578160200160208202803683370190505b50915060005b6000858152600760209081526040808320878452909152902054811015610baf576000858152600b60209081526040808320878452825280832084845290915290205483516001600160a01b0390911690849083908110610b8557610b85614f97565b6001600160a01b039092166020928302919091019091015280610ba781614f7e565b915050610b22565b505092915050565b610bbf61390c565b818060035411610be15760405162461bcd60e51b815260040161061d90614f0c565b6000838152600960205260409020548390610c0e5760405162461bcd60e51b815260040161061d90614f2d565b6000848152600660205260408120600201546001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa158015610c73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c979190614fad565b905083811015610cd45760405162461bcd60e51b81526020600482015260086024820152674552525f562e323560c01b604482015260640161061d565b6000610cdf866117d8565b600087815260076020908152604080832084845290915290206008810154600690910154919250610d0f91614f65565b421115610d2e5760405162461bcd60e51b815260040161061d90614fc6565b6000868152600a602090815260408083203380855290835281842085855283528184208a8552600884528285209185529252909120805415801590610d7557506001820154155b15610d88578054610d8890899033613a27565b600088815260076020908152604080832086845290915281206002018054899290610db4908490614f65565b9250508190555086826001016000828254610dcf9190614f65565b909155505080548314610de0578281555b610e073360008a8152600660205260409020600201546001600160a01b031690308a613b6b565b604051878152889033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a3505050505050610e4d60018055565b5050565b610e596139cd565b838060035411610e7b5760405162461bcd60e51b815260040161061d90614f0c565b60008581526006602081815260409283902060058101546007820154919093015484518a81529283019390935292810187905260608101929092526080820185905260a082015260c081018390527fe688636a9e39148b1edbd6665d6d4a56d8629d5047d44472c5d06bca67f90a4f9060e00160405180910390a150600093845260066020819052604090942060058101939093556007830191909155910155565b610f2561390c565b610f2d6139cd565b80610160015151600214610f6d5760405162461bcd60e51b81526020600482015260076024820152664552525f562e3360c81b604482015260640161061d565b60208101516001600160a01b0316610fb15760405162461bcd60e51b81526020600482015260076024820152664552525f562e3560c81b604482015260640161061d565b60006001600160a01b0316816101600151600081518110610fd457610fd4614f97565b60200260200101516001600160a01b03160361101c5760405162461bcd60e51b815260206004820152600760248201526622a9292fab171b60c91b604482015260640161061d565b60006001600160a01b031681610160015160018151811061103f5761103f614f97565b60200260200101516001600160a01b0316036110875760405162461bcd60e51b81526020600482015260076024820152664552525f562e3760c81b604482015260640161061d565b60055460408051636621387d60e01b815290516000926001600160a01b031691636621387d916004808301926020929190829003018187875af11580156110d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110f69190614fe8565b905060405180610260016040528083600001516001600160a01b0316815260200183602001516001600160a01b03168152602001826001600160a01b031681526020018360a0015181526020018360c0015181526020018360400151815260200183606001518152602001836080015181526020018360e001518152602001836101000151815260200183610120015181526020016000815260200160008152602001600081526020016000815260200183610160015181526020018361014001516001600160a01b03168152602001600015158152602001836101800151151581525060066000600354815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e082015181600701556101008201518160080155610120820151816009015561014082015181600a015561016082015181600b015561018082015181600c01556101a082015181600d01556101c082015181600e01556101e082015181600f01908051906020019061131292919061493d565b5061020082015160109091018054610220840151610240909401511515600160a81b0260ff60a81b19941515600160a01b026001600160a81b03199092166001600160a01b0390941693909317179290921617905560038054908190600061137983614f7e565b9091555050600480548451602086015160405163121f2aaf60e21b81529384018590526001600160a01b03918216602485015281166044840152169063487caabc90606401600060405180830381600087803b1580156113d857600080fd5b505af11580156113ec573d6000803e3d6000fd5b505050508260a00151817f7fd83957c6ca0ef0e76db72271f206d0e451f24ed6ae9f86da9d4c888253a1f48560400151866080015187610180015188610160015189600001518a602001518b61010001518c6101200151604051611457989796959493929190615005565b60405180910390a350506109a560018055565b61147261390c565b61147a6139cd565b80806003541161149c5760405162461bcd60e51b815260040161061d90614f0c565b6000828152600660205260409020600a810154600b8201546114be9190614f65565b4210156114f85760405162461bcd60e51b81526020600482015260086024820152674552525f562e333160c01b604482015260640161061d565b42600b820155600e8101548061153b5760405162461bcd60e51b81526020600482015260086024820152674552525f562e333560c01b604482015260640161061d565b81546040516370a0823160e01b815230600482015282916001600160a01b0316906370a0823190602401602060405180830381865afa158015611582573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a69190614fad565b10156115df5760405162461bcd60e51b815260206004820152600860248201526722a9292fab17199960c11b604482015260640161061d565b6000600e8301819055600f8301805482906115fc576115fc614f97565b6000918252602082200154600f850180546001600160a01b03909216935090600190811061162c5761162c614f97565b6000918252602090912001546001600160a01b031690507f783ad58a3e77de8f48cbc5b7b85e67eda94545ca6ac909671c4d4461eedecc56868361167160028761505e565b604080519384526001600160a01b0390921660208401529082015260600160405180910390a17f783ad58a3e77de8f48cbc5b7b85e67eda94545ca6ac909671c4d4461eedecc5686826116c560028761505e565b604080519384526001600160a01b0390921660208401529082015260600160405180910390a161170c826116fa60028661505e565b86546001600160a01b03169190613965565b61171b816116fa60028661505e565b50505050506109a560018055565b6117316139cd565b8280600354116117535760405162461bcd60e51b815260040161061d90614f0c565b6000848152600660209081526040918290206003810154600a9091015483518881529283019190915281830186905260608201526080810184905290517f7eb9abb1c530a0c5c9e6a557c080514b3d38d59cb1d2a0fc085405d67f991a029181900360a00190a1506000928352600660205260409092206003810191909155600a0155565b60008180600354116117fc5760405162461bcd60e51b815260040161061d90614f0c565b60008381526009602052604090205483906118295760405162461bcd60e51b815260040161061d90614f2d565b60008481526009602052604090205461184490600190615080565b949350505050565b6118546139cd565b61185e6000613ba3565b565b61186861390c565b80806003541161188a5760405162461bcd60e51b815260040161061d90614f0c565b60008281526009602052604090205482906118b75760405162461bcd60e51b815260040161061d90614f2d565b6000838152600660205260408120906118cf856117d8565b600086815260076020908152604080832084845290915290206008810154600682015492935090916119019190614f65565b421061193a5760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c8d60c21b604482015260640161061d565b6000868152600a602090815260408083203384528252808320858452909152902080548061197a5760405162461bcd60e51b815260040161061d90615093565b6000808355600184018054839290611993908490615080565b909155505084546119ae906001600160a01b03163383613965565b60008881526008602090815260408083203384529091528120600384015490919081905b8360020154811015611a2f5760008c8152600c602090815260408083203384528252808320848452909152902060010154611a0d9084614f65565b925081611a1981614f7e565b9250508080611a2790614f7e565b9150506119d2565b5080836002016000828254611a449190615080565b90915550506001880154611a62906001600160a01b03163384613965565b60008b8152600b602090815260408083208a845282528083206002890154845290915280822054885483529120546001600160a01b03918216911603611ad75760008b8152600b602090815260408083208a8452825280832089548452909152902080546001600160a01b0319169055611c3a565b6000600b60008d8152602001908152602001600020600089815260200190815260200160002060008860000154815260200190815260200160002060009054906101000a90046001600160a01b031690506000600b60008e815260200190815260200160002060008a815260200190815260200160002060008960000154815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555080600b60008e815260200190815260200160002060008a815260200190815260200160002060008860020154815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508560020154600a60008e81526020019081526020016000206000836001600160a01b03166001600160a01b0316815260200190815260200160002060008a815260200190815260200160002060020181905550505b6000600286018190558654908790611c51836150b5565b909155505060048501805460ff1916905560408051338152602081018d905280820186905290517f4d03849d7cc7e6aa8812404182c6821dda42bc4a15e60a2055dee048bff349109181900360600190a1505050505050505050506109a560018055565b611cbd61390c565b808060035411611cdf5760405162461bcd60e51b815260040161061d90614f0c565b60008281526008602090815260408083203384529091529020805480611d325760405162461bcd60e51b815260206004820152600860248201526722a9292fab17199b60c11b604482015260640161061d565b611d3d848233613a27565b5060009055506109a560018055565b611d546139cd565b818060035411611d765760405162461bcd60e51b815260040161061d90614f0c565b6001600160a01b038216611db75760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c4d60c21b604482015260640161061d565b600083815260066020526040908190206010015490517f94c8b3c75ba308c40e2ac10a7a6e9e5ff5c689a07cddb9a6b7a1227682e4728391611e209186916001600160a01b03169086909283526001600160a01b03918216602084015216604082015260600190565b60405180910390a15060009182526006602052604090912060100180546001600160a01b0319166001600160a01b03909216919091179055565b611e6261390c565b611e6a6139cd565b818060035411611e8c5760405162461bcd60e51b815260040161061d90614f0c565b600083815260066020526040902060108101546001600160a01b0316611edf5760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c4d60c21b604482015260640161061d565b80600c015460000361204d5760008481526007602090815260408083208380529091529020600381015415612005578054600782015414611f4d5760405162461bcd60e51b815260206004820152600860248201526722a9292fab17189b60c11b604482015260640161061d565b600085815260096020526040902054600110611f965760405162461bcd60e51b81526020600482015260086024820152674552525f562e313760c01b604482015260640161061d565b600c82018054906000611fa883614f7e565b9091555050600085815260076020908152604080832060018452909152902060088101546006820154611fdb9190614f65565b421015611ffa5760405162461bcd60e51b815260040161061d906150cc565b600301849055612047565b806008015481600601546120199190614f65565b4210156120385760405162461bcd60e51b815260040161061d906150cc565b600d8201849055600381018490555b50612162565b6000848152600760208181526040808420600c86015485529091529091208054910154146120a85760405162461bcd60e51b815260206004820152600860248201526722a9292fab17189b60c11b604482015260640161061d565b600c810180549060006120ba83614f7e565b9091555050600c8101546000858152600960205260409020541161210b5760405162461bcd60e51b81526020600482015260086024820152674552525f562e313760c01b604482015260640161061d565b6000848152600760209081526040808320600c850154845290915290206008810154600682015461213c9190614f65565b42101561215b5760405162461bcd60e51b815260040161061d906150cc565b6003018390555b61216c8484613bf3565b600c81015460408051868152602081019290925281018490527f0215487829526ab31001252991ed70c90a9a6aaefa14f9ee2bda4b64db3bbf7a9060600160405180910390a15050610e4d60018055565b6121f16040518060a00160405280600081526020016000815260200160008152602001600081526020016000151581525090565b8380600354116122135760405162461bcd60e51b815260040161061d90614f0c565b50506000928352600a602090815260408085206001600160a01b03909416855292815282842091845290815291819020815160a08101835281548152600182015493810193909352600281015491830191909152600381015460608301526004015460ff161515608082015290565b61228a6139cd565b8080600354116122ac5760405162461bcd60e51b815260040161061d90614f0c565b600082815260066020526040902060100154600160a01b900460ff16156122ff5760405162461bcd60e51b81526020600482015260076024820152664552525f562e3960c81b604482015260640161061d565b6000828152600660205260409081902060108101805460ff60a01b1916600160a01b17905560048054600890920154925163ddaf8d0760e01b81526001600160a01b039092169263ddaf8d07926123629287929101918252602082015260400190565b600060405180830381600087803b15801561237c57600080fd5b505af1158015612390573d6000803e3d6000fd5b5050505060405180610120016040528060008152602001600081526020016000815260200160008152602001600081526020016000815260200142815260200160008152602001600660008581526020019081526020016000206008015481525060076000848152602001908152602001600020600060096000868152602001908152602001600020548152602001908152602001600020600082015181600001556020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c0820151816006015560e0820151816007015561010082015181600801559050506009600083815260200190815260200160002060008154809291906124aa90614f7e565b909155505060405182907f74e534d9ee9babee8812594b75f57a2889a16ee1b6c28c2de11b5afffad02b8390600090a25050565b6124e661390c565b8080600354116125085760405162461bcd60e51b815260040161061d90614f0c565b60008281526009602052604090205482906125355760405162461bcd60e51b815260040161061d90614f2d565b60008381526006602052604081209061254d856117d8565b6000868152600760209081526040808320848452909152902060088101546006820154929350909161257f9190614f65565b42106125b85760405162461bcd60e51b815260206004820152600860248201526711549497d58b8c8d60c21b604482015260640161061d565b6000868152600a602090815260408083203380855290835281842086855283528184208a855260088452828520918552925290912060018201548061260f5760405162461bcd60e51b815260040161061d90615093565b600060018401819055825560028401548111156126595760405162461bcd60e51b815260206004820152600860248201526722a9292fab17191b60c11b604482015260640161061d565b8084600201600082825461266d9190615080565b9091555050600286015461268b906001600160a01b03163383613965565b60408051338152602081018b905280820183905290517f39e2e01794006bc1f63835af5c05db790beca4bfb40de3f02cc3ddf22dccc0fb9181900360600190a150505050505050506109a560018055565b61272b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b82806003541161274d5760405162461bcd60e51b815260040161061d90614f0c565b600084815260096020526040902054849061277a5760405162461bcd60e51b815260040161061d90614f2d565b505050600091825260076020818152604080852093855292815292829020825161012081018452815481526001820154948101949094526002810154928401929092526003820154606084015260048201546080840152600582015460a0840152600682015460c084015281015460e08301526008015461010082015290565b61280261390c565b61280a6139cd565b80806003541161282c5760405162461bcd60e51b815260040161061d90614f0c565b600082815260066020818152604080842081516102608101835281546001600160a01b0390811682526001830154811682860152600283015416818401526003820154606082015260048201546080820152600582015460a08201529381015460c0850152600781015460e085015260088101546101008501526009810154610120850152600a810154610140850152600b810154610160850152600c810154610180850152600d8101546101a0850152600e8101546101c0850152600f8101805483518186028101860190945280845291936101e0860193929083018282801561294057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612922575b5050509183525050601091909101546001600160a01b03811660208084019190915260ff600160a01b830481161515604080860191909152600160a81b90930416151560609384015260008781526007808352838220610180870151835283529083902083516101208101855281548152600182015493810193909352600281015493830193909352600383015493820184905260048301546080830152600583015460a0830152600683015460c083015282015460e0820152600890910154610100820152919250612a405760405162461bcd60e51b81526020600482015260086024820152674552525f562e323760c01b604482015260640161061d565b60e081015115612a7d5760405162461bcd60e51b815260206004820152600860248201526708aa4a4beac5c64760c31b604482015260640161061d565b8060200151600003612a90575050612a9c565b612a998461426f565b50505b506109a560018055565b612aae6139cd565b818060035411612ad05760405162461bcd60e51b815260040161061d90614f0c565b8151600214612b0b5760405162461bcd60e51b81526020600482015260076024820152664552525f562e3360c81b604482015260640161061d565b60006001600160a01b031682600081518110612b2957612b29614f97565b60200260200101516001600160a01b031603612b715760405162461bcd60e51b815260206004820152600760248201526622a9292fab171b60c91b604482015260640161061d565b60006001600160a01b031682600181518110612b8f57612b8f614f97565b60200260200101516001600160a01b031603612bd75760405162461bcd60e51b81526020600482015260076024820152664552525f562e3760c81b604482015260640161061d565b6000838152600660205260409081902090517f13f42559ce1a76db34ac3c5b7141308c1e286e00168793042025be3e556bfc5591612c1c918691600f019086906150ee565b60405180910390a160008381526006602090815260409091208351612c4992600f9092019185019061493d565b50505050565b612c5761390c565b612c5f6139cd565b808060035411612c815760405162461bcd60e51b815260040161061d90614f0c565b60008281526007602081815260408084206006808452828620600c01548652908352938190208151610120810183528154815260018201549381019390935260028101549183019190915260038101546060830181905260048201546080840152600582015460a08401529381015460c08301529182015460e082015260089091015461010082015290612d425760405162461bcd60e51b81526020600482015260086024820152674552525f562e323760c01b604482015260640161061d565b8060e00151600003612d815760405162461bcd60e51b81526020600482015260086024820152674552525f562e323960c01b604482015260640161061d565b805160e082015110612dc05760405162461bcd60e51b815260206004820152600860248201526704552525f562e33360c41b604482015260640161061d565b612dc98361426f565b50506109a560018055565b612ddc6139cd565b818060035411612dfe5760405162461bcd60e51b815260040161061d90614f0c565b6040805184815283151560208201527f77f1fcfcce67dc392d64f842056d2ec06c80986c47c910f7e79c5b23a2738d74910160405180910390a1506000918252600660205260409091206010018054911515600160a81b0260ff60a81b19909216919091179055565b612f2460405180610260016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016060815260200160006001600160a01b031681526020016000151581526020016000151581525090565b818060035411612f465760405162461bcd60e51b815260040161061d90614f0c565b60008381526006602081815260409283902083516102608101855281546001600160a01b0390811682526001830154811682850152600283015416818601526003820154606082015260048201546080820152600582015460a08201529281015460c0840152600781015460e084015260088101546101008401526009810154610120840152600a810154610140840152600b810154610160840152600c810154610180840152600d8101546101a0840152600e8101546101c0840152600f81018054855181850281018501909652808652939491936101e086019383018282801561305b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161303d575b5050509183525050601091909101546001600160a01b038116602083015260ff600160a01b8204811615156040840152600160a81b9091041615156060909101529392505050565b6130ab61390c565b8180600354116130cd5760405162461bcd60e51b815260040161061d90614f0c565b600083815260066020526040902060100154600160a81b900460ff16156131205760405162461bcd60e51b815260206004820152600760248201526622a9292fab171960c91b604482015260640161061d565b6000838152600660205260409020600781015483116131515760405162461bcd60e51b815260040161061d90615093565b805483906001600160a01b03166370a08231336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156131a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131cc9190614fad565b10156132055760405162461bcd60e51b81526020600482015260086024820152674552525f562e323160c01b604482015260640161061d565b6000613210856117d8565b600086815260076020908152604080832084845290915290206008810154600682015492935090916132429190614f65565b4211156132615760405162461bcd60e51b815260040161061d90614fc6565b6000868152600a602090815260408083203380855290835281842086855283528184208a8552600884528285209185529252909120600585015460018401546132ab908990614f65565b11156132e45760405162461bcd60e51b81526020600482015260086024820152674552525f562e323360c01b604482015260640161061d565b6004805460405163a616f34560e01b81529182018a90526001600160a01b03169063a616f34590602401600060405180830381600087803b15801561332857600080fd5b505af115801561333c573d6000803e3d6000fd5b505050506004858101548154604051635cf4ee9160e01b81529283018b9052602483018a905260009261271092916001600160a01b031690635cf4ee9190604401602060405180830381865afa15801561339a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133be9190614fad565b6133c8919061515d565b6133d2919061505e565b90506133ee3360018801546001600160a01b0316903084613b6b565b6000898152600c602090815260408083203384528252808320600286015484529091528120600385015490910361342a57600283015460038501555b60028301805490600061343c83614f7e565b909155505042815560018101829055600484015460ff166134fe5760068701548554613469906001614f65565b11156134a25760405162461bcd60e51b815260206004820152600860248201526722a9292fab17191960c11b604482015260640161061d565b60008a8152600b60209081526040808320898452825280832088548452909152812080546001600160a01b031916331790558554600286018190559086906134e983614f7e565b909155505060048401805460ff191660011790555b888560010160008282546135129190614f65565b9091555050865461352e906001600160a01b031633308c613b6b565b888460000160008282546135429190614f65565b909155505060408051308152602081018b905281518c9233927fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7929081900390910190a35050505050505050610e4d60018055565b60408051808201909152600080825260208201528380600354116135cd5760405162461bcd60e51b815260040161061d90614f0c565b50506000928352600c602090815260408085206001600160a01b03909416855292815282842091845290815291819020815180830190925280548252600101549181019190915290565b61361f6139cd565b6001600160a01b0381166136845760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161061d565b6109a581613ba3565b6136956139cd565b60025460408051918252602082018390527f3e8b961c6e8faa03d0d285994a4dade0cf480a9fedd1c35c093d5d4f0a3ed061910160405180910390a1600255565b6136de6139cd565b60005b6003548110156137a8576000818152600660205260409020600101546001600160a01b038084169116036137425760405162461bcd60e51b815260206004820152600860248201526711549497d58b8ccd60c21b604482015260640161061d565b6000818152600660205260409020546001600160a01b038084169116036137965760405162461bcd60e51b815260206004820152600860248201526711549497d58b8ccd60c21b604482015260640161061d565b806137a081614f7e565b9150506136e1565b506109a5336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156137f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138159190614fad565b6001600160a01b0384169190613965565b61382e6139cd565b8280600354116138505760405162461bcd60e51b815260040161061d90614f0c565b600084815260066020908152604091829020600901548251878152918201529081018490527f1b4a3d3abd483e39f6952818ff6bf53403dbeee05ef875088ed214b3c7fdb1049060600160405180910390a16000848152600660209081526040918290206004015482519081529081018490527fa984efc2bef6d7e91d9620c90f6f42b4cfb5913bf1db59801626e4a8eabacb38910160405180910390a150600092835260066020526040909220600981019190915560040155565b60026001540361395e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161061d565b6002600155565b6040516001600160a01b0383166024820152604481018290526139c890849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614371565b505050565b6000546001600160a01b0316331461185e5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161061d565b60008381526007602090815260408083208584528252808320868452600a83528184206001600160a01b0386168552835281842086855290925282206001015490918115613af15760008360020154846005015484613a86919061515d565b613a90919061505e565b9050613a9c8183614f65565b604080518981526001600160a01b0388166020820152908101889052606081018390529092507f25d1255c398e637e957d1d04691db7d1b318bc88e20deda96f2c8714f8297e389060800160405180910390a1505b8015613b1a57600086815260066020526040902054613b1a906001600160a01b03168583613965565b604080518781526001600160a01b03861660208201529081018290527ffd8c040503c4beb434790f3a2e972438d06ece0dc342f58052f2f9fd385828779060600160405180910390a1505050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612c499085906323b872dd60e01b90608401613991565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008111613c2e5760405162461bcd60e51b81526020600482015260086024820152674552525f562e333560c01b604482015260640161061d565b6000613c3a8383614446565b60008581526007602081815260408084206006808452828620600c8101548088529285528387208c885282865284516102608101865282546001600160a01b0390811682526001840154811682890152600284015416818701526003830154606082015260048301546080820152600583015460a08201529282015460c08401529581015460e083015260088101546101008301526009810154610120830152600a810154610140830152600b810154610160830152610180820192909252600d8201546101a0820152600e8201546101c0820152600f82018054845181870281018701909552808552989a5096985093969495939490936101e0860193909190830182828015613d7457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613d56575b5050509183525050601091909101546001600160a01b0380821660208085019190915260ff600160a01b840481161515604080870191909152600160a81b90940416151560609094019390935283820151825163313ce56760e01b8152925194955060009491169263313ce56792600480820193918290030181865afa158015613e02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e269190615174565b613e3190600a61527b565b9050600085828560010154613e46919061515d565b613e50919061505e565b9050600082856002015488613e65919061515d565b613e6f919061505e565b60048601839055600586018190556002860154909150821115613f57576000856002015483613e9e9190615080565b9050600085604001516001600160a01b031663a0712d68836040518263ffffffff1660e01b8152600401613ed491815260200190565b6020604051808303816000875af1158015613ef3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f17919061528a565b905080613f505760405162461bcd60e51b815260206004820152600760248201526608aa4a4beac5c760cb1b604482015260640161061d565b5050614020565b6000828660020154613f699190615080565b9050801561401e576040808601519051630852cd8d60e31b8152600481018390526000916001600160a01b0316906342966c68906024016020604051808303816000875af1158015613fbf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe3919061528a565b90508061401c5760405162461bcd60e51b815260206004820152600760248201526611549497d58b8d60ca1b604482015260640161061d565b505b505b61402a8682614f65565b85600101541061416f576000868287600101546140479190615080565b6140519190615080565b905080156141695784516040516370a0823160e01b815230600482015282916001600160a01b0316906370a0823190602401602060405180830381865afa1580156140a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140c49190614fad565b10156140fd5760405162461bcd60e51b815260206004820152600860248201526722a9292fab17189960c11b604482015260640161061d565b610200850151855161411b916001600160a01b039091169083613965565b610200850151604080516001600160a01b039092168252602082018390528a9130917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a35b5061425c565b60018501546000906141818884614f65565b61418b9190615080565b85516102008701516040516370a0823160e01b81526001600160a01b03918216600482015292935083929116906370a0823190602401602060405180830381865afa1580156141de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142029190614fad565b101561423b5760405162461bcd60e51b81526020600482015260086024820152674552525f562e313360c01b604482015260640161061d565b610200850151855161425a916001600160a01b03909116903084613b6b565b505b61426588614616565b5050505050505050565b600081815260076020818152604080842060068352818520600c015485529091529091209081015460048201545b8254821080156142ae57506002545a115b15614367576000848152600b6020908152604080832060068352818420600c0154808552908352818420868552835281842054888552600a84528285206001600160a01b03909116808652908452828520918552925282205460018601549192909161431a838661515d565b614324919061505e565b9050801561435257600087815260066020526040902060020154614352906001600160a01b03168483613965565b8461435c81614f7e565b95505050505061429d565b5060079091015550565b60006143c6826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661481a9092919063ffffffff16565b90508051600014806143e75750808060200190518101906143e7919061528a565b6139c85760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161061d565b60008281526006602090815260408083206002810154825163313ce56760e01b815292518594929385936001600160a01b039093169263313ce567926004808401938290030181865afa1580156144a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144c59190615174565b6144d090600a61527b565b905060008260020160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614529573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061454d9190614fad565b9050600093508594508583600d0154101561460c578161271082856003015486600d01548a61457c9190615080565b614586919061515d565b614590919061515d565b61459a919061505e565b6145a4919061505e565b9350831561460c578583600d01819055508383600e0160008282546145c99190614f65565b909155506000905084836145dd848a61515d565b6145e7919061505e565b6145f19190615080565b9050816145fe848361515d565b614608919061505e565b9550505b5050509250929050565b60008181526009602052604090205481906146435760405162461bcd60e51b815260040161061d90614f2d565b600061464e836117d8565b60008481526007602090815260408083208484529091529020600881015460069091015491925061467e91614f65565b42106139c85760008381526007602090815260408083208484529091529020600301546146bd5760405162461bcd60e51b815260040161061d90614fc6565b6040805161012081018252600080825260208201819052818301819052606082018190526080820181905260a082015260048054925163022684db60e41b8152908101869052909160c08301916001600160a01b03909116906322684db090602401602060405180830381865afa15801561473c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147609190614fad565b8152600060208083018290528682526006808252604080842060089081015495820195909552888452600780845281852060098086528387208054885291865283872089518155898701516001820155938901516002850155606089015160038501556080890151600485015560a0890151600585015560c08901519484019490945560e08801519183019190915561010090960151940193909355868252919091528154919061481083614f7e565b9190505550505050565b6060611844848460008585600080866001600160a01b0316858760405161484191906152cb565b60006040518083038185875af1925050503d806000811461487e576040519150601f19603f3d011682016040523d82523d6000602084013e614883565b606091505b50915091506148948783838761489f565b979650505050505050565b6060831561490e578251600003614907576001600160a01b0385163b6149075760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161061d565b5081611844565b61184483838151156149235781518083602001fd5b8060405162461bcd60e51b815260040161061d91906152e7565b828054828255906000526020600020908101928215614992579160200282015b8281111561499257825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061495d565b5061499e9291506149a2565b5090565b5b8082111561499e57600081556001016149a3565b6001600160a01b03811681146109a557600080fd5b80356149d7816149b7565b919050565b600080604083850312156149ef57600080fd5b823591506020830135614a01816149b7565b809150509250929050565b600060208284031215614a1e57600080fd5b5035919050565b60008060408385031215614a3857600080fd5b50508035926020909101359150565b600081518084526020808501945080840160005b83811015614a805781516001600160a01b031687529582019590820190600101614a5b565b509495945050505050565b602081526000614a9e6020830184614a47565b9392505050565b60008060008060808587031215614abb57600080fd5b5050823594602084013594506040840135936060013592509050565b634e487b7160e01b600052604160045260246000fd5b6040516101a0810167ffffffffffffffff81118282101715614b1157614b11614ad7565b60405290565b600082601f830112614b2857600080fd5b8135602067ffffffffffffffff80831115614b4557614b45614ad7565b8260051b604051601f19603f83011681018181108482111715614b6a57614b6a614ad7565b604052938452858101830193838101925087851115614b8857600080fd5b83870191505b84821015614894578135614ba1816149b7565b83529183019190830190614b8e565b80151581146109a557600080fd5b80356149d781614bb0565b600060208284031215614bdb57600080fd5b813567ffffffffffffffff80821115614bf357600080fd5b908301906101a08286031215614c0857600080fd5b614c10614aed565b614c19836149cc565b8152614c27602084016149cc565b602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e0820152610100808401358183015250610120808401358183015250610140614c8e8185016149cc565b908201526101608381013583811115614ca657600080fd5b614cb288828701614b17565b8284015250506101809150614cc8828401614bbe565b91810191909152949350505050565b600080600060608486031215614cec57600080fd5b505081359360208301359350604090920135919050565b600080600060608486031215614d1857600080fd5b833592506020840135614d2a816149b7565b929592945050506040919091013590565b60008060408385031215614d4e57600080fd5b82359150602083013567ffffffffffffffff811115614d6c57600080fd5b614d7885828601614b17565b9150509250929050565b60008060408385031215614d9557600080fd5b823591506020830135614a0181614bb0565b60208152614dc16020820183516001600160a01b03169052565b60006020830151614ddd60408401826001600160a01b03169052565b5060408301516001600160a01b038116606084015250606083015160808381019190915283015160a08084019190915283015160c08084019190915283015160e08084019190915283015161010080840191909152830151610120808401919091528301516101408084019190915283015161016080840191909152830151610180808401919091528301516101a0808401919091528301516101c0808401919091528301516101e080840191909152830151610260610200808501829052614eaa610280860184614a47565b90860151909250610220614ec8868201836001600160a01b03169052565b8601519050610240614edd8682018315159052565b90950151151593019290925250919050565b600060208284031215614f0157600080fd5b8135614a9e816149b7565b6020808252600790820152664552525f562e3160c81b604082015260600190565b60208082526008908201526704552525f562e31360c41b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115614f7857614f78614f4f565b92915050565b600060018201614f9057614f90614f4f565b5060010190565b634e487b7160e01b600052603260045260246000fd5b600060208284031215614fbf57600080fd5b5051919050565b6020808252600890820152674552525f562e333760c01b604082015260600190565b600060208284031215614ffa57600080fd5b8151614a9e816149b7565b60006101008a8352896020840152881515604084015280606084015261502d81840189614a47565b6001600160a01b0397881660808501529590961660a08301525060c081019290925260e09091015295945050505050565b60008261507b57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115614f7857614f78614f4f565b60208082526008908201526704552525f562e32360c41b604082015260600190565b6000816150c4576150c4614f4f565b506000190190565b60208082526008908201526708aa4a4beac5c62760c31b604082015260600190565b60006060820185835260206060818501528186548084526080860191508760005282600020935060005b8181101561513d5784546001600160a01b031683526001948501949284019201615118565b505084810360408601526151518187614a47565b98975050505050505050565b8082028115828204841417614f7857614f78614f4f565b60006020828403121561518657600080fd5b815160ff81168114614a9e57600080fd5b600181815b808511156151d25781600019048211156151b8576151b8614f4f565b808516156151c557918102915b93841c939080029061519c565b509250929050565b6000826151e957506001614f78565b816151f657506000614f78565b816001811461520c576002811461521657615232565b6001915050614f78565b60ff84111561522757615227614f4f565b50506001821b614f78565b5060208310610133831016604e8410600b8410161715615255575081810a614f78565b61525f8383615197565b806000190482111561527357615273614f4f565b029392505050565b6000614a9e60ff8416836151da565b60006020828403121561529c57600080fd5b8151614a9e81614bb0565b60005b838110156152c25781810151838201526020016152aa565b50506000910152565b600082516152dd8184602087016152a7565b9190910192915050565b60208152600082518060208401526153068160408501602087016152a7565b601f01601f1916919091016040019291505056fea26469706673582212206a672514675c083a61390eae01e0e3fa1d7ade8ebc48d43175dffde3fa34334364736f6c63430008120033
Loading...
Loading
Loading...
Loading
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.