Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 11446775 | 1392 days ago | IN | 0 ETH | 0.18454878 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
Curation
Compiler Version
v0.7.4+commit.3f05b770
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.7.3; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../bancor/BancorFormula.sol"; import "../upgrades/GraphUpgradeable.sol"; import "./CurationStorage.sol"; import "./ICuration.sol"; import "./GraphCurationToken.sol"; /** * @title Curation contract * @dev Allows curators to signal on subgraph deployments that might be relevant to indexers by * staking Graph Tokens (GRT). Additionally, curators earn fees from the Query Market related to the * subgraph deployment they curate. * A curators deposit goes to a curation pool along with the deposits of other curators, * only one such pool exists for each subgraph deployment. * The contract mints Graph Curation Shares (GCS) according to a bonding curve for each individual * curation pool where GRT is deposited. * Holders can burn GCS using this contract to get GRT tokens back according to the * bonding curve. */ contract Curation is CurationV1Storage, GraphUpgradeable, ICuration { using SafeMath for uint256; // 100% in parts per million uint32 private constant MAX_PPM = 1000000; // Amount of signal you get with your minimum token deposit uint256 private constant SIGNAL_PER_MINIMUM_DEPOSIT = 1e18; // 1 signal as 18 decimal number // -- Events -- /** * @dev Emitted when `curator` deposited `tokens` on `subgraphDeploymentID` as curation signal. * The `curator` receives `signal` amount according to the curation pool bonding curve. * An amount of `curationTax` will be collected and burned. */ event Signalled( address indexed curator, bytes32 indexed subgraphDeploymentID, uint256 tokens, uint256 signal, uint256 curationTax ); /** * @dev Emitted when `curator` burned `signal` for a `subgraphDeploymentID`. * The curator will receive `tokens` according to the value of the bonding curve. */ event Burned( address indexed curator, bytes32 indexed subgraphDeploymentID, uint256 tokens, uint256 signal ); /** * @dev Emitted when `tokens` amount were collected for `subgraphDeploymentID` as part of fees * distributed by an indexer from query fees received from state channels. */ event Collected(bytes32 indexed subgraphDeploymentID, uint256 tokens); /** * @dev Initialize this contract. */ function initialize( address _controller, address _bondingCurve, uint32 _defaultReserveRatio, uint32 _curationTaxPercentage, uint256 _minimumCurationDeposit ) external onlyImpl { Managed._initialize(_controller); require(_bondingCurve != address(0), "Bonding curve must be set"); bondingCurve = _bondingCurve; // Settings _setDefaultReserveRatio(_defaultReserveRatio); _setCurationTaxPercentage(_curationTaxPercentage); _setMinimumCurationDeposit(_minimumCurationDeposit); } /** * @dev Set the default reserve ratio percentage for a curation pool. * @notice Update the default reserver ratio to `_defaultReserveRatio` * @param _defaultReserveRatio Reserve ratio (in PPM) */ function setDefaultReserveRatio(uint32 _defaultReserveRatio) external override onlyGovernor { _setDefaultReserveRatio(_defaultReserveRatio); } /** * @dev Internal: Set the default reserve ratio percentage for a curation pool. * @notice Update the default reserver ratio to `_defaultReserveRatio` * @param _defaultReserveRatio Reserve ratio (in PPM) */ function _setDefaultReserveRatio(uint32 _defaultReserveRatio) private { // Reserve Ratio must be within 0% to 100% (inclusive, in PPM) require(_defaultReserveRatio > 0, "Default reserve ratio must be > 0"); require( _defaultReserveRatio <= MAX_PPM, "Default reserve ratio cannot be higher than MAX_PPM" ); defaultReserveRatio = _defaultReserveRatio; emit ParameterUpdated("defaultReserveRatio"); } /** * @dev Set the minimum deposit amount for curators. * @notice Update the minimum deposit amount to `_minimumCurationDeposit` * @param _minimumCurationDeposit Minimum amount of tokens required deposit */ function setMinimumCurationDeposit(uint256 _minimumCurationDeposit) external override onlyGovernor { _setMinimumCurationDeposit(_minimumCurationDeposit); } /** * @dev Internal: Set the minimum deposit amount for curators. * @notice Update the minimum deposit amount to `_minimumCurationDeposit` * @param _minimumCurationDeposit Minimum amount of tokens required deposit */ function _setMinimumCurationDeposit(uint256 _minimumCurationDeposit) private { require(_minimumCurationDeposit > 0, "Minimum curation deposit cannot be 0"); minimumCurationDeposit = _minimumCurationDeposit; emit ParameterUpdated("minimumCurationDeposit"); } /** * @dev Set the curation tax percentage to charge when a curator deposits GRT tokens. * @param _percentage Curation tax percentage charged when depositing GRT tokens */ function setCurationTaxPercentage(uint32 _percentage) external override onlyGovernor { _setCurationTaxPercentage(_percentage); } /** * @dev Internal: Set the curation tax percentage to charge when a curator deposits GRT tokens. * @param _percentage Curation tax percentage charged when depositing GRT tokens */ function _setCurationTaxPercentage(uint32 _percentage) private { require( _percentage <= MAX_PPM, "Curation tax percentage must be below or equal to MAX_PPM" ); _curationTaxPercentage = _percentage; emit ParameterUpdated("curationTaxPercentage"); } /** * @dev Assign Graph Tokens collected as curation fees to the curation pool reserve. * This function can only be called by the Staking contract and will do the bookeeping of * transferred tokens into this contract. * @param _subgraphDeploymentID SubgraphDeployment where funds should be allocated as reserves * @param _tokens Amount of Graph Tokens to add to reserves */ function collect(bytes32 _subgraphDeploymentID, uint256 _tokens) external override { // Only Staking contract is authorized as caller require(msg.sender == address(staking()), "Caller must be the staking contract"); // Must be curated to accept tokens require( isCurated(_subgraphDeploymentID), "Subgraph deployment must be curated to collect fees" ); // Collect new funds into reserve CurationPool storage curationPool = pools[_subgraphDeploymentID]; curationPool.tokens = curationPool.tokens.add(_tokens); emit Collected(_subgraphDeploymentID, _tokens); } /** * @dev Deposit Graph Tokens in exchange for signal of a SubgraphDeployment curation pool. * @param _subgraphDeploymentID Subgraph deployment pool from where to mint signal * @param _tokensIn Amount of Graph Tokens to deposit * @param _signalOutMin Expected minimum amount of signal to receive * @return Signal minted and deposit tax */ function mint( bytes32 _subgraphDeploymentID, uint256 _tokensIn, uint256 _signalOutMin ) external override notPartialPaused returns (uint256, uint256) { // Need to deposit some funds require(_tokensIn > 0, "Cannot deposit zero tokens"); // Exchange GRT tokens for GCS of the subgraph pool (uint256 signalOut, uint256 curationTax) = tokensToSignal(_subgraphDeploymentID, _tokensIn); // Slippage protection require(signalOut >= _signalOutMin, "Slippage protection"); address curator = msg.sender; CurationPool storage curationPool = pools[_subgraphDeploymentID]; // If it hasn't been curated before then initialize the curve if (!isCurated(_subgraphDeploymentID)) { // Initialize curationPool.reserveRatio = defaultReserveRatio; // If no signal token for the pool - create one if (address(curationPool.gcs) == address(0)) { // TODO: Use a minimal proxy to reduce gas cost // https://github.com/graphprotocol/contracts/issues/405 // --abarmat-- 20201113 curationPool.gcs = IGraphCurationToken( address(new GraphCurationToken(address(this))) ); } } // Trigger update rewards calculation snapshot _updateRewards(_subgraphDeploymentID); // Transfer tokens from the curator to this contract // This needs to happen after _updateRewards snapshot as that function // is using balanceOf(curation) IGraphToken graphToken = graphToken(); require( graphToken.transferFrom(curator, address(this), _tokensIn), "Cannot transfer tokens to deposit" ); // Burn withdrawal fees if (curationTax > 0) { graphToken.burn(curationTax); } // Update curation pool curationPool.tokens = curationPool.tokens.add(_tokensIn.sub(curationTax)); curationPool.gcs.mint(curator, signalOut); emit Signalled(curator, _subgraphDeploymentID, _tokensIn, signalOut, curationTax); return (signalOut, curationTax); } /** * @dev Return an amount of signal to get tokens back. * @notice Burn _signal from the SubgraphDeployment curation pool * @param _subgraphDeploymentID SubgraphDeployment the curator is returning signal * @param _signalIn Amount of signal to return * @param _tokensOutMin Expected minimum amount of tokens to receive * @return Tokens returned */ function burn( bytes32 _subgraphDeploymentID, uint256 _signalIn, uint256 _tokensOutMin ) external override notPartialPaused returns (uint256) { address curator = msg.sender; // Validations require(_signalIn > 0, "Cannot burn zero signal"); require( getCuratorSignal(curator, _subgraphDeploymentID) >= _signalIn, "Cannot burn more signal than you own" ); // Get the amount of tokens to refund based on returned signal uint256 tokensOut = signalToTokens(_subgraphDeploymentID, _signalIn); // Slippage protection require(tokensOut >= _tokensOutMin, "Slippage protection"); // Trigger update rewards calculation _updateRewards(_subgraphDeploymentID); // Update curation pool CurationPool storage curationPool = pools[_subgraphDeploymentID]; curationPool.tokens = curationPool.tokens.sub(tokensOut); curationPool.gcs.burnFrom(curator, _signalIn); // If all signal burnt delete the curation pool if (getCurationPoolSignal(_subgraphDeploymentID) == 0) { delete pools[_subgraphDeploymentID]; } // Return the tokens to the curator require(graphToken().transfer(curator, tokensOut), "Error sending curator tokens"); emit Burned(curator, _subgraphDeploymentID, tokensOut, _signalIn); return tokensOut; } /** * @dev Check if any GRT tokens are deposited for a SubgraphDeployment. * @param _subgraphDeploymentID SubgraphDeployment to check if curated * @return True if curated */ function isCurated(bytes32 _subgraphDeploymentID) public override view returns (bool) { return pools[_subgraphDeploymentID].tokens > 0; } /** * @dev Get the amount of signal a curator has in a curation pool. * @param _curator Curator owning the signal tokens * @param _subgraphDeploymentID Subgraph deployment curation pool * @return Amount of signal owned by a curator for the subgraph deployment */ function getCuratorSignal(address _curator, bytes32 _subgraphDeploymentID) public override view returns (uint256) { if (address(pools[_subgraphDeploymentID].gcs) == address(0)) { return 0; } return pools[_subgraphDeploymentID].gcs.balanceOf(_curator); } /** * @dev Get the amount of signal in a curation pool. * @param _subgraphDeploymentID Subgraph deployment curation poool * @return Amount of signal minted for the subgraph deployment */ function getCurationPoolSignal(bytes32 _subgraphDeploymentID) public override view returns (uint256) { if (address(pools[_subgraphDeploymentID].gcs) == address(0)) { return 0; } return pools[_subgraphDeploymentID].gcs.totalSupply(); } /** * @dev Get the amount of token reserves in a curation pool. * @param _subgraphDeploymentID Subgraph deployment curation poool * @return Amount of token reserves in the curation pool */ function getCurationPoolTokens(bytes32 _subgraphDeploymentID) external override view returns (uint256) { return pools[_subgraphDeploymentID].tokens; } /** * @dev Get curation tax percentage * @return Amount the curation tax percentage in PPM */ function curationTaxPercentage() external override view returns (uint32) { return _curationTaxPercentage; } /** * @dev Calculate amount of signal that can be bought with tokens in a curation pool. * This function considers and excludes the deposit tax. * @param _subgraphDeploymentID Subgraph deployment to mint signal * @param _tokensIn Amount of tokens used to mint signal * @return Amount of signal that can be bought and tokens subtracted for the tax */ function tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn) public override view returns (uint256, uint256) { uint256 curationTax = _tokensIn.mul(uint256(_curationTaxPercentage)).div(MAX_PPM); uint256 signalOut = _tokensToSignal(_subgraphDeploymentID, _tokensIn.sub(curationTax)); return (signalOut, curationTax); } /** * @dev Calculate amount of signal that can be bought with tokens in a curation pool. * @param _subgraphDeploymentID Subgraph deployment to mint signal * @param _tokensIn Amount of tokens used to mint signal * @return Amount of signal that can be bought with tokens */ function _tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn) private view returns (uint256) { // Get curation pool tokens and signal CurationPool memory curationPool = pools[_subgraphDeploymentID]; // Init curation pool if (curationPool.tokens == 0) { require( _tokensIn >= minimumCurationDeposit, "Curation deposit is below minimum required" ); return BancorFormula(bondingCurve) .calculatePurchaseReturn( SIGNAL_PER_MINIMUM_DEPOSIT, minimumCurationDeposit, defaultReserveRatio, _tokensIn.sub(minimumCurationDeposit) ) .add(SIGNAL_PER_MINIMUM_DEPOSIT); } return BancorFormula(bondingCurve).calculatePurchaseReturn( getCurationPoolSignal(_subgraphDeploymentID), curationPool.tokens, curationPool.reserveRatio, _tokensIn ); } /** * @dev Calculate number of tokens to get when burning signal from a curation pool. * @param _subgraphDeploymentID Subgraph deployment to burn signal * @param _signalIn Amount of signal to burn * @return Amount of tokens to get for an amount of signal */ function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signalIn) public override view returns (uint256) { CurationPool memory curationPool = pools[_subgraphDeploymentID]; uint256 curationPoolSignal = getCurationPoolSignal(_subgraphDeploymentID); require( curationPool.tokens > 0, "Subgraph deployment must be curated to perform calculations" ); require( curationPoolSignal >= _signalIn, "Signal must be above or equal to signal issued in the curation pool" ); return BancorFormula(bondingCurve).calculateSaleReturn( curationPoolSignal, curationPool.tokens, curationPool.reserveRatio, _signalIn ); } /** * @dev Triggers an update of rewards due to a change in signal. * @param _subgraphDeploymentID Subgraph deployment updated */ function _updateRewards(bytes32 _subgraphDeploymentID) private { IRewardsManager rewardsManager = rewardsManager(); if (address(rewardsManager) != address(0)) { rewardsManager.onSubgraphSignalUpdate(_subgraphDeploymentID); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @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) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @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 sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @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) { // 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 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts 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) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts 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 mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.7.3; import "@openzeppelin/contracts/math/SafeMath.sol"; contract BancorFormula { using SafeMath for uint256; uint16 public constant version = 6; uint256 private constant ONE = 1; uint32 private constant MAX_RATIO = 1000000; uint8 private constant MIN_PRECISION = 32; uint8 private constant MAX_PRECISION = 127; /** * @dev Auto-generated via 'PrintIntScalingFactors.py' */ uint256 private constant FIXED_1 = 0x080000000000000000000000000000000; uint256 private constant FIXED_2 = 0x100000000000000000000000000000000; uint256 private constant MAX_NUM = 0x200000000000000000000000000000000; /** * @dev Auto-generated via 'PrintLn2ScalingFactors.py' */ uint256 private constant LN2_NUMERATOR = 0x3f80fe03f80fe03f80fe03f80fe03f8; uint256 private constant LN2_DENOMINATOR = 0x5b9de1d10bf4103d647b0955897ba80; /** * @dev Auto-generated via 'PrintFunctionOptimalLog.py' and 'PrintFunctionOptimalExp.py' */ uint256 private constant OPT_LOG_MAX_VAL = 0x15bf0a8b1457695355fb8ac404e7a79e3; uint256 private constant OPT_EXP_MAX_VAL = 0x800000000000000000000000000000000; /** * @dev Auto-generated via 'PrintFunctionConstructor.py' */ uint256[128] private maxExpArray; constructor() { // maxExpArray[ 0] = 0x6bffffffffffffffffffffffffffffffff; // maxExpArray[ 1] = 0x67ffffffffffffffffffffffffffffffff; // maxExpArray[ 2] = 0x637fffffffffffffffffffffffffffffff; // maxExpArray[ 3] = 0x5f6fffffffffffffffffffffffffffffff; // maxExpArray[ 4] = 0x5b77ffffffffffffffffffffffffffffff; // maxExpArray[ 5] = 0x57b3ffffffffffffffffffffffffffffff; // maxExpArray[ 6] = 0x5419ffffffffffffffffffffffffffffff; // maxExpArray[ 7] = 0x50a2ffffffffffffffffffffffffffffff; // maxExpArray[ 8] = 0x4d517fffffffffffffffffffffffffffff; // maxExpArray[ 9] = 0x4a233fffffffffffffffffffffffffffff; // maxExpArray[ 10] = 0x47165fffffffffffffffffffffffffffff; // maxExpArray[ 11] = 0x4429afffffffffffffffffffffffffffff; // maxExpArray[ 12] = 0x415bc7ffffffffffffffffffffffffffff; // maxExpArray[ 13] = 0x3eab73ffffffffffffffffffffffffffff; // maxExpArray[ 14] = 0x3c1771ffffffffffffffffffffffffffff; // maxExpArray[ 15] = 0x399e96ffffffffffffffffffffffffffff; // maxExpArray[ 16] = 0x373fc47fffffffffffffffffffffffffff; // maxExpArray[ 17] = 0x34f9e8ffffffffffffffffffffffffffff; // maxExpArray[ 18] = 0x32cbfd5fffffffffffffffffffffffffff; // maxExpArray[ 19] = 0x30b5057fffffffffffffffffffffffffff; // maxExpArray[ 20] = 0x2eb40f9fffffffffffffffffffffffffff; // maxExpArray[ 21] = 0x2cc8340fffffffffffffffffffffffffff; // maxExpArray[ 22] = 0x2af09481ffffffffffffffffffffffffff; // maxExpArray[ 23] = 0x292c5bddffffffffffffffffffffffffff; // maxExpArray[ 24] = 0x277abdcdffffffffffffffffffffffffff; // maxExpArray[ 25] = 0x25daf6657fffffffffffffffffffffffff; // maxExpArray[ 26] = 0x244c49c65fffffffffffffffffffffffff; // maxExpArray[ 27] = 0x22ce03cd5fffffffffffffffffffffffff; // maxExpArray[ 28] = 0x215f77c047ffffffffffffffffffffffff; // maxExpArray[ 29] = 0x1fffffffffffffffffffffffffffffffff; // maxExpArray[ 30] = 0x1eaefdbdabffffffffffffffffffffffff; // maxExpArray[ 31] = 0x1d6bd8b2ebffffffffffffffffffffffff; maxExpArray[32] = 0x1c35fedd14ffffffffffffffffffffffff; maxExpArray[33] = 0x1b0ce43b323fffffffffffffffffffffff; maxExpArray[34] = 0x19f0028ec1ffffffffffffffffffffffff; maxExpArray[35] = 0x18ded91f0e7fffffffffffffffffffffff; maxExpArray[36] = 0x17d8ec7f0417ffffffffffffffffffffff; maxExpArray[37] = 0x16ddc6556cdbffffffffffffffffffffff; maxExpArray[38] = 0x15ecf52776a1ffffffffffffffffffffff; maxExpArray[39] = 0x15060c256cb2ffffffffffffffffffffff; maxExpArray[40] = 0x1428a2f98d72ffffffffffffffffffffff; maxExpArray[41] = 0x13545598e5c23fffffffffffffffffffff; maxExpArray[42] = 0x1288c4161ce1dfffffffffffffffffffff; maxExpArray[43] = 0x11c592761c666fffffffffffffffffffff; maxExpArray[44] = 0x110a688680a757ffffffffffffffffffff; maxExpArray[45] = 0x1056f1b5bedf77ffffffffffffffffffff; maxExpArray[46] = 0x0faadceceeff8bffffffffffffffffffff; maxExpArray[47] = 0x0f05dc6b27edadffffffffffffffffffff; maxExpArray[48] = 0x0e67a5a25da4107fffffffffffffffffff; maxExpArray[49] = 0x0dcff115b14eedffffffffffffffffffff; maxExpArray[50] = 0x0d3e7a392431239fffffffffffffffffff; maxExpArray[51] = 0x0cb2ff529eb71e4fffffffffffffffffff; maxExpArray[52] = 0x0c2d415c3db974afffffffffffffffffff; maxExpArray[53] = 0x0bad03e7d883f69bffffffffffffffffff; maxExpArray[54] = 0x0b320d03b2c343d5ffffffffffffffffff; maxExpArray[55] = 0x0abc25204e02828dffffffffffffffffff; maxExpArray[56] = 0x0a4b16f74ee4bb207fffffffffffffffff; maxExpArray[57] = 0x09deaf736ac1f569ffffffffffffffffff; maxExpArray[58] = 0x0976bd9952c7aa957fffffffffffffffff; maxExpArray[59] = 0x09131271922eaa606fffffffffffffffff; maxExpArray[60] = 0x08b380f3558668c46fffffffffffffffff; maxExpArray[61] = 0x0857ddf0117efa215bffffffffffffffff; maxExpArray[62] = 0x07ffffffffffffffffffffffffffffffff; maxExpArray[63] = 0x07abbf6f6abb9d087fffffffffffffffff; maxExpArray[64] = 0x075af62cbac95f7dfa7fffffffffffffff; maxExpArray[65] = 0x070d7fb7452e187ac13fffffffffffffff; maxExpArray[66] = 0x06c3390ecc8af379295fffffffffffffff; maxExpArray[67] = 0x067c00a3b07ffc01fd6fffffffffffffff; maxExpArray[68] = 0x0637b647c39cbb9d3d27ffffffffffffff; maxExpArray[69] = 0x05f63b1fc104dbd39587ffffffffffffff; maxExpArray[70] = 0x05b771955b36e12f7235ffffffffffffff; maxExpArray[71] = 0x057b3d49dda84556d6f6ffffffffffffff; maxExpArray[72] = 0x054183095b2c8ececf30ffffffffffffff; maxExpArray[73] = 0x050a28be635ca2b888f77fffffffffffff; maxExpArray[74] = 0x04d5156639708c9db33c3fffffffffffff; maxExpArray[75] = 0x04a23105873875bd52dfdfffffffffffff; maxExpArray[76] = 0x0471649d87199aa990756fffffffffffff; maxExpArray[77] = 0x04429a21a029d4c1457cfbffffffffffff; maxExpArray[78] = 0x0415bc6d6fb7dd71af2cb3ffffffffffff; maxExpArray[79] = 0x03eab73b3bbfe282243ce1ffffffffffff; maxExpArray[80] = 0x03c1771ac9fb6b4c18e229ffffffffffff; maxExpArray[81] = 0x0399e96897690418f785257fffffffffff; maxExpArray[82] = 0x0373fc456c53bb779bf0ea9fffffffffff; maxExpArray[83] = 0x034f9e8e490c48e67e6ab8bfffffffffff; maxExpArray[84] = 0x032cbfd4a7adc790560b3337ffffffffff; maxExpArray[85] = 0x030b50570f6e5d2acca94613ffffffffff; maxExpArray[86] = 0x02eb40f9f620fda6b56c2861ffffffffff; maxExpArray[87] = 0x02cc8340ecb0d0f520a6af58ffffffffff; maxExpArray[88] = 0x02af09481380a0a35cf1ba02ffffffffff; maxExpArray[89] = 0x0292c5bdd3b92ec810287b1b3fffffffff; maxExpArray[90] = 0x0277abdcdab07d5a77ac6d6b9fffffffff; maxExpArray[91] = 0x025daf6654b1eaa55fd64df5efffffffff; maxExpArray[92] = 0x0244c49c648baa98192dce88b7ffffffff; maxExpArray[93] = 0x022ce03cd5619a311b2471268bffffffff; maxExpArray[94] = 0x0215f77c045fbe885654a44a0fffffffff; maxExpArray[95] = 0x01ffffffffffffffffffffffffffffffff; maxExpArray[96] = 0x01eaefdbdaaee7421fc4d3ede5ffffffff; maxExpArray[97] = 0x01d6bd8b2eb257df7e8ca57b09bfffffff; maxExpArray[98] = 0x01c35fedd14b861eb0443f7f133fffffff; maxExpArray[99] = 0x01b0ce43b322bcde4a56e8ada5afffffff; maxExpArray[100] = 0x019f0028ec1fff007f5a195a39dfffffff; maxExpArray[101] = 0x018ded91f0e72ee74f49b15ba527ffffff; maxExpArray[102] = 0x017d8ec7f04136f4e5615fd41a63ffffff; maxExpArray[103] = 0x016ddc6556cdb84bdc8d12d22e6fffffff; maxExpArray[104] = 0x015ecf52776a1155b5bd8395814f7fffff; maxExpArray[105] = 0x015060c256cb23b3b3cc3754cf40ffffff; maxExpArray[106] = 0x01428a2f98d728ae223ddab715be3fffff; maxExpArray[107] = 0x013545598e5c23276ccf0ede68034fffff; maxExpArray[108] = 0x01288c4161ce1d6f54b7f61081194fffff; maxExpArray[109] = 0x011c592761c666aa641d5a01a40f17ffff; maxExpArray[110] = 0x0110a688680a7530515f3e6e6cfdcdffff; maxExpArray[111] = 0x01056f1b5bedf75c6bcb2ce8aed428ffff; maxExpArray[112] = 0x00faadceceeff8a0890f3875f008277fff; maxExpArray[113] = 0x00f05dc6b27edad306388a600f6ba0bfff; maxExpArray[114] = 0x00e67a5a25da41063de1495d5b18cdbfff; maxExpArray[115] = 0x00dcff115b14eedde6fc3aa5353f2e4fff; maxExpArray[116] = 0x00d3e7a3924312399f9aae2e0f868f8fff; maxExpArray[117] = 0x00cb2ff529eb71e41582cccd5a1ee26fff; maxExpArray[118] = 0x00c2d415c3db974ab32a51840c0b67edff; maxExpArray[119] = 0x00bad03e7d883f69ad5b0a186184e06bff; maxExpArray[120] = 0x00b320d03b2c343d4829abd6075f0cc5ff; maxExpArray[121] = 0x00abc25204e02828d73c6e80bcdb1a95bf; maxExpArray[122] = 0x00a4b16f74ee4bb2040a1ec6c15fbbf2df; maxExpArray[123] = 0x009deaf736ac1f569deb1b5ae3f36c130f; maxExpArray[124] = 0x00976bd9952c7aa957f5937d790ef65037; maxExpArray[125] = 0x009131271922eaa6064b73a22d0bd4f2bf; maxExpArray[126] = 0x008b380f3558668c46c91c49a2f8e967b9; maxExpArray[127] = 0x00857ddf0117efa215952912839f6473e6; } /** * @dev given a token supply, reserve balance, ratio and a deposit amount (in the reserve token), * calculates the return for a given conversion (in the main token) * * Formula: * Return = _supply * ((1 + _depositAmount / _reserveBalance) ^ (_reserveRatio / 1000000) - 1) * * @param _supply token total supply * @param _reserveBalance total reserve balance * @param _reserveRatio reserve ratio, represented in ppm, 1-1000000 * @param _depositAmount deposit amount, in reserve token * * @return purchase return amount */ function calculatePurchaseReturn( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _depositAmount ) public view returns (uint256) { // validate input require( _supply > 0 && _reserveBalance > 0 && _reserveRatio > 0 && _reserveRatio <= MAX_RATIO, "invalid parameters" ); // special case for 0 deposit amount if (_depositAmount == 0) return 0; // special case if the ratio = 100% if (_reserveRatio == MAX_RATIO) return _supply.mul(_depositAmount) / _reserveBalance; uint256 result; uint8 precision; uint256 baseN = _depositAmount.add(_reserveBalance); (result, precision) = power(baseN, _reserveBalance, _reserveRatio, MAX_RATIO); uint256 temp = _supply.mul(result) >> precision; return temp - _supply; } /** * @dev given a token supply, reserve balance, ratio and a sell amount (in the main token), * calculates the return for a given conversion (in the reserve token) * * Formula: * Return = _reserveBalance * (1 - (1 - _sellAmount / _supply) ^ (1000000 / _reserveRatio)) * * @param _supply token total supply * @param _reserveBalance total reserve * @param _reserveRatio constant reserve Ratio, represented in ppm, 1-1000000 * @param _sellAmount sell amount, in the token itself * * @return sale return amount */ function calculateSaleReturn( uint256 _supply, uint256 _reserveBalance, uint32 _reserveRatio, uint256 _sellAmount ) public view returns (uint256) { // validate input require( _supply > 0 && _reserveBalance > 0 && _reserveRatio > 0 && _reserveRatio <= MAX_RATIO && _sellAmount <= _supply, "invalid parameters" ); // special case for 0 sell amount if (_sellAmount == 0) return 0; // special case for selling the entire supply if (_sellAmount == _supply) return _reserveBalance; // special case if the ratio = 100% if (_reserveRatio == MAX_RATIO) return _reserveBalance.mul(_sellAmount) / _supply; uint256 result; uint8 precision; uint256 baseD = _supply - _sellAmount; (result, precision) = power(_supply, baseD, MAX_RATIO, _reserveRatio); uint256 temp1 = _reserveBalance.mul(result); uint256 temp2 = _reserveBalance << precision; return (temp1 - temp2) / result; } /** * @dev given two reserve balances/ratios and a sell amount (in the first reserve token), * calculates the return for a conversion from the first reserve token to the second reserve token (in the second reserve token) * note that prior to version 4, you should use 'calculateCrossConnectorReturn' instead * * Formula: * Return = _toReserveBalance * (1 - (_fromReserveBalance / (_fromReserveBalance + _amount)) ^ (_fromReserveRatio / _toReserveRatio)) * * @param _fromReserveBalance input reserve balance * @param _fromReserveRatio input reserve ratio, represented in ppm, 1-1000000 * @param _toReserveBalance output reserve balance * @param _toReserveRatio output reserve ratio, represented in ppm, 1-1000000 * @param _amount input reserve amount * * @return second reserve amount */ function calculateCrossReserveReturn( uint256 _fromReserveBalance, uint32 _fromReserveRatio, uint256 _toReserveBalance, uint32 _toReserveRatio, uint256 _amount ) public view returns (uint256) { // validate input require( _fromReserveBalance > 0 && _fromReserveRatio > 0 && _fromReserveRatio <= MAX_RATIO && _toReserveBalance > 0 && _toReserveRatio > 0 && _toReserveRatio <= MAX_RATIO ); // special case for equal ratios if (_fromReserveRatio == _toReserveRatio) return _toReserveBalance.mul(_amount) / _fromReserveBalance.add(_amount); uint256 result; uint8 precision; uint256 baseN = _fromReserveBalance.add(_amount); (result, precision) = power(baseN, _fromReserveBalance, _fromReserveRatio, _toReserveRatio); uint256 temp1 = _toReserveBalance.mul(result); uint256 temp2 = _toReserveBalance << precision; return (temp1 - temp2) / result; } /** * @dev given a smart token supply, reserve balance, total ratio and an amount of requested smart tokens, * calculates the amount of reserve tokens required for purchasing the given amount of smart tokens * * Formula: * Return = _reserveBalance * (((_supply + _amount) / _supply) ^ (MAX_RATIO / _totalRatio) - 1) * * @param _supply smart token supply * @param _reserveBalance reserve token balance * @param _totalRatio total ratio, represented in ppm, 2-2000000 * @param _amount requested amount of smart tokens * * @return amount of reserve tokens */ function calculateFundCost( uint256 _supply, uint256 _reserveBalance, uint32 _totalRatio, uint256 _amount ) public view returns (uint256) { // validate input require( _supply > 0 && _reserveBalance > 0 && _totalRatio > 1 && _totalRatio <= MAX_RATIO * 2 ); // special case for 0 amount if (_amount == 0) return 0; // special case if the total ratio = 100% if (_totalRatio == MAX_RATIO) return (_amount.mul(_reserveBalance) - 1) / _supply + 1; uint256 result; uint8 precision; uint256 baseN = _supply.add(_amount); (result, precision) = power(baseN, _supply, MAX_RATIO, _totalRatio); uint256 temp = ((_reserveBalance.mul(result) - 1) >> precision) + 1; return temp - _reserveBalance; } /** * @dev given a smart token supply, reserve balance, total ratio and an amount of smart tokens to liquidate, * calculates the amount of reserve tokens received for selling the given amount of smart tokens * * Formula: * Return = _reserveBalance * (1 - ((_supply - _amount) / _supply) ^ (MAX_RATIO / _totalRatio)) * * @param _supply smart token supply * @param _reserveBalance reserve token balance * @param _totalRatio total ratio, represented in ppm, 2-2000000 * @param _amount amount of smart tokens to liquidate * * @return amount of reserve tokens */ function calculateLiquidateReturn( uint256 _supply, uint256 _reserveBalance, uint32 _totalRatio, uint256 _amount ) public view returns (uint256) { // validate input require( _supply > 0 && _reserveBalance > 0 && _totalRatio > 1 && _totalRatio <= MAX_RATIO * 2 && _amount <= _supply ); // special case for 0 amount if (_amount == 0) return 0; // special case for liquidating the entire supply if (_amount == _supply) return _reserveBalance; // special case if the total ratio = 100% if (_totalRatio == MAX_RATIO) return _amount.mul(_reserveBalance) / _supply; uint256 result; uint8 precision; uint256 baseD = _supply - _amount; (result, precision) = power(_supply, baseD, MAX_RATIO, _totalRatio); uint256 temp1 = _reserveBalance.mul(result); uint256 temp2 = _reserveBalance << precision; return (temp1 - temp2) / result; } /** * @dev General Description: * Determine a value of precision. * Calculate an integer approximation of (_baseN / _baseD) ^ (_expN / _expD) * 2 ^ precision. * Return the result along with the precision used. * * Detailed Description: * Instead of calculating "base ^ exp", we calculate "e ^ (log(base) * exp)". * The value of "log(base)" is represented with an integer slightly smaller than "log(base) * 2 ^ precision". * The larger "precision" is, the more accurately this value represents the real value. * However, the larger "precision" is, the more bits are required in order to store this value. * And the exponentiation function, which takes "x" and calculates "e ^ x", is limited to a maximum exponent (maximum value of "x"). * This maximum exponent depends on the "precision" used, and it is given by "maxExpArray[precision] >> (MAX_PRECISION - precision)". * Hence we need to determine the highest precision which can be used for the given input, before calling the exponentiation function. * This allows us to compute "base ^ exp" with maximum accuracy and without exceeding 256 bits in any of the intermediate computations. * This functions assumes that "_expN < 2 ^ 256 / log(MAX_NUM - 1)", otherwise the multiplication should be replaced with a "safeMul". * Since we rely on unsigned-integer arithmetic and "base < 1" ==> "log(base) < 0", this function does not support "_baseN < _baseD". */ function power( uint256 _baseN, uint256 _baseD, uint32 _expN, uint32 _expD ) internal view returns (uint256, uint8) { require(_baseN < MAX_NUM); uint256 baseLog; uint256 base = (_baseN * FIXED_1) / _baseD; if (base < OPT_LOG_MAX_VAL) { baseLog = optimalLog(base); } else { baseLog = generalLog(base); } uint256 baseLogTimesExp = (baseLog * _expN) / _expD; if (baseLogTimesExp < OPT_EXP_MAX_VAL) { return (optimalExp(baseLogTimesExp), MAX_PRECISION); } else { uint8 precision = findPositionInMaxExpArray(baseLogTimesExp); return ( generalExp(baseLogTimesExp >> (MAX_PRECISION - precision), precision), precision ); } } /** * @dev computes log(x / FIXED_1) * FIXED_1. * This functions assumes that "x >= FIXED_1", because the output would be negative otherwise. */ function generalLog(uint256 x) internal pure returns (uint256) { uint256 res = 0; // If x >= 2, then we compute the integer part of log2(x), which is larger than 0. if (x >= FIXED_2) { uint8 count = floorLog2(x / FIXED_1); x >>= count; // now x < 2 res = count * FIXED_1; } // If x > 1, then we compute the fraction part of log2(x), which is larger than 0. if (x > FIXED_1) { for (uint8 i = MAX_PRECISION; i > 0; --i) { x = (x * x) / FIXED_1; // now 1 < x < 4 if (x >= FIXED_2) { x >>= 1; // now 1 < x < 2 res += ONE << (i - 1); } } } return (res * LN2_NUMERATOR) / LN2_DENOMINATOR; } /** * @dev computes the largest integer smaller than or equal to the binary logarithm of the input. */ function floorLog2(uint256 _n) internal pure returns (uint8) { uint8 res = 0; if (_n < 256) { // At most 8 iterations while (_n > 1) { _n >>= 1; res += 1; } } else { // Exactly 8 iterations for (uint8 s = 128; s > 0; s >>= 1) { if (_n >= (ONE << s)) { _n >>= s; res |= s; } } } return res; } /** * @dev the global "maxExpArray" is sorted in descending order, and therefore the following statements are equivalent: * - This function finds the position of [the smallest value in "maxExpArray" larger than or equal to "x"] * - This function finds the highest position of [a value in "maxExpArray" larger than or equal to "x"] */ function findPositionInMaxExpArray(uint256 _x) internal view returns (uint8) { uint8 lo = MIN_PRECISION; uint8 hi = MAX_PRECISION; while (lo + 1 < hi) { uint8 mid = (lo + hi) / 2; if (maxExpArray[mid] >= _x) lo = mid; else hi = mid; } if (maxExpArray[hi] >= _x) return hi; if (maxExpArray[lo] >= _x) return lo; require(false); return 0; } /** * @dev this function can be auto-generated by the script 'PrintFunctionGeneralExp.py'. * it approximates "e ^ x" via maclaurin summation: "(x^0)/0! + (x^1)/1! + ... + (x^n)/n!". * it returns "e ^ (x / 2 ^ precision) * 2 ^ precision", that is, the result is upshifted for accuracy. * the global "maxExpArray" maps each "precision" to "((maximumExponent + 1) << (MAX_PRECISION - precision)) - 1". * the maximum permitted value for "x" is therefore given by "maxExpArray[precision] >> (MAX_PRECISION - precision)". */ function generalExp(uint256 _x, uint8 _precision) internal pure returns (uint256) { uint256 xi = _x; uint256 res = 0; xi = (xi * _x) >> _precision; res += xi * 0x3442c4e6074a82f1797f72ac0000000; // add x^02 * (33! / 02!) xi = (xi * _x) >> _precision; res += xi * 0x116b96f757c380fb287fd0e40000000; // add x^03 * (33! / 03!) xi = (xi * _x) >> _precision; res += xi * 0x045ae5bdd5f0e03eca1ff4390000000; // add x^04 * (33! / 04!) xi = (xi * _x) >> _precision; res += xi * 0x00defabf91302cd95b9ffda50000000; // add x^05 * (33! / 05!) xi = (xi * _x) >> _precision; res += xi * 0x002529ca9832b22439efff9b8000000; // add x^06 * (33! / 06!) xi = (xi * _x) >> _precision; res += xi * 0x00054f1cf12bd04e516b6da88000000; // add x^07 * (33! / 07!) xi = (xi * _x) >> _precision; res += xi * 0x0000a9e39e257a09ca2d6db51000000; // add x^08 * (33! / 08!) xi = (xi * _x) >> _precision; res += xi * 0x000012e066e7b839fa050c309000000; // add x^09 * (33! / 09!) xi = (xi * _x) >> _precision; res += xi * 0x000001e33d7d926c329a1ad1a800000; // add x^10 * (33! / 10!) xi = (xi * _x) >> _precision; res += xi * 0x0000002bee513bdb4a6b19b5f800000; // add x^11 * (33! / 11!) xi = (xi * _x) >> _precision; res += xi * 0x00000003a9316fa79b88eccf2a00000; // add x^12 * (33! / 12!) xi = (xi * _x) >> _precision; res += xi * 0x0000000048177ebe1fa812375200000; // add x^13 * (33! / 13!) xi = (xi * _x) >> _precision; res += xi * 0x0000000005263fe90242dcbacf00000; // add x^14 * (33! / 14!) xi = (xi * _x) >> _precision; res += xi * 0x000000000057e22099c030d94100000; // add x^15 * (33! / 15!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000057e22099c030d9410000; // add x^16 * (33! / 16!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000052b6b54569976310000; // add x^17 * (33! / 17!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000004985f67696bf748000; // add x^18 * (33! / 18!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000003dea12ea99e498000; // add x^19 * (33! / 19!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000031880f2214b6e000; // add x^20 * (33! / 20!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000000025bcff56eb36000; // add x^21 * (33! / 21!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000000001b722e10ab1000; // add x^22 * (33! / 22!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000001317c70077000; // add x^23 * (33! / 23!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000cba84aafa00; // add x^24 * (33! / 24!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000082573a0a00; // add x^25 * (33! / 25!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000005035ad900; // add x^26 * (33! / 26!) xi = (xi * _x) >> _precision; res += xi * 0x000000000000000000000002f881b00; // add x^27 * (33! / 27!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000001b29340; // add x^28 * (33! / 28!) xi = (xi * _x) >> _precision; res += xi * 0x00000000000000000000000000efc40; // add x^29 * (33! / 29!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000007fe0; // add x^30 * (33! / 30!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000000420; // add x^31 * (33! / 31!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000000021; // add x^32 * (33! / 32!) xi = (xi * _x) >> _precision; res += xi * 0x0000000000000000000000000000001; // add x^33 * (33! / 33!) return res / 0x688589cc0e9505e2f2fee5580000000 + _x + (ONE << _precision); // divide by 33! and then add x^1 / 1! + x^0 / 0! } /** * @dev computes log(x / FIXED_1) * FIXED_1 * Input range: FIXED_1 <= x <= LOG_EXP_MAX_VAL - 1 * Auto-generated via 'PrintFunctionOptimalLog.py' * Detailed description: * - Rewrite the input as a product of natural exponents and a single residual r, such that 1 < r < 2 * - The natural logarithm of each (pre-calculated) exponent is the degree of the exponent * - The natural logarithm of r is calculated via Taylor series for log(1 + x), where x = r - 1 * - The natural logarithm of the input is calculated by summing up the intermediate results above * - For example: log(250) = log(e^4 * e^1 * e^0.5 * 1.021692859) = 4 + 1 + 0.5 + log(1 + 0.021692859) */ function optimalLog(uint256 x) internal pure returns (uint256) { uint256 res = 0; uint256 y; uint256 z; uint256 w; if (x >= 0xd3094c70f034de4b96ff7d5b6f99fcd8) { res += 0x40000000000000000000000000000000; x = (x * FIXED_1) / 0xd3094c70f034de4b96ff7d5b6f99fcd8; } // add 1 / 2^1 if (x >= 0xa45af1e1f40c333b3de1db4dd55f29a7) { res += 0x20000000000000000000000000000000; x = (x * FIXED_1) / 0xa45af1e1f40c333b3de1db4dd55f29a7; } // add 1 / 2^2 if (x >= 0x910b022db7ae67ce76b441c27035c6a1) { res += 0x10000000000000000000000000000000; x = (x * FIXED_1) / 0x910b022db7ae67ce76b441c27035c6a1; } // add 1 / 2^3 if (x >= 0x88415abbe9a76bead8d00cf112e4d4a8) { res += 0x08000000000000000000000000000000; x = (x * FIXED_1) / 0x88415abbe9a76bead8d00cf112e4d4a8; } // add 1 / 2^4 if (x >= 0x84102b00893f64c705e841d5d4064bd3) { res += 0x04000000000000000000000000000000; x = (x * FIXED_1) / 0x84102b00893f64c705e841d5d4064bd3; } // add 1 / 2^5 if (x >= 0x8204055aaef1c8bd5c3259f4822735a2) { res += 0x02000000000000000000000000000000; x = (x * FIXED_1) / 0x8204055aaef1c8bd5c3259f4822735a2; } // add 1 / 2^6 if (x >= 0x810100ab00222d861931c15e39b44e99) { res += 0x01000000000000000000000000000000; x = (x * FIXED_1) / 0x810100ab00222d861931c15e39b44e99; } // add 1 / 2^7 if (x >= 0x808040155aabbbe9451521693554f733) { res += 0x00800000000000000000000000000000; x = (x * FIXED_1) / 0x808040155aabbbe9451521693554f733; } // add 1 / 2^8 z = y = x - FIXED_1; w = (y * y) / FIXED_1; res += (z * (0x100000000000000000000000000000000 - y)) / 0x100000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^01 / 01 - y^02 / 02 res += (z * (0x0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - y)) / 0x200000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^03 / 03 - y^04 / 04 res += (z * (0x099999999999999999999999999999999 - y)) / 0x300000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^05 / 05 - y^06 / 06 res += (z * (0x092492492492492492492492492492492 - y)) / 0x400000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^07 / 07 - y^08 / 08 res += (z * (0x08e38e38e38e38e38e38e38e38e38e38e - y)) / 0x500000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^09 / 09 - y^10 / 10 res += (z * (0x08ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8b - y)) / 0x600000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^11 / 11 - y^12 / 12 res += (z * (0x089d89d89d89d89d89d89d89d89d89d89 - y)) / 0x700000000000000000000000000000000; z = (z * w) / FIXED_1; // add y^13 / 13 - y^14 / 14 res += (z * (0x088888888888888888888888888888888 - y)) / 0x800000000000000000000000000000000; // add y^15 / 15 - y^16 / 16 return res; } /** * @dev computes e ^ (x / FIXED_1) * FIXED_1 * input range: 0 <= x <= OPT_EXP_MAX_VAL - 1 * auto-generated via 'PrintFunctionOptimalExp.py' * Detailed description: * - Rewrite the input as a sum of binary exponents and a single residual r, as small as possible * - The exponentiation of each binary exponent is given (pre-calculated) * - The exponentiation of r is calculated via Taylor series for e^x, where x = r * - The exponentiation of the input is calculated by multiplying the intermediate results above * - For example: e^5.521692859 = e^(4 + 1 + 0.5 + 0.021692859) = e^4 * e^1 * e^0.5 * e^0.021692859 */ function optimalExp(uint256 x) internal pure returns (uint256) { uint256 res = 0; uint256 y; uint256 z; z = y = x % 0x10000000000000000000000000000000; // get the input modulo 2^(-3) z = (z * y) / FIXED_1; res += z * 0x10e1b3be415a0000; // add y^02 * (20! / 02!) z = (z * y) / FIXED_1; res += z * 0x05a0913f6b1e0000; // add y^03 * (20! / 03!) z = (z * y) / FIXED_1; res += z * 0x0168244fdac78000; // add y^04 * (20! / 04!) z = (z * y) / FIXED_1; res += z * 0x004807432bc18000; // add y^05 * (20! / 05!) z = (z * y) / FIXED_1; res += z * 0x000c0135dca04000; // add y^06 * (20! / 06!) z = (z * y) / FIXED_1; res += z * 0x0001b707b1cdc000; // add y^07 * (20! / 07!) z = (z * y) / FIXED_1; res += z * 0x000036e0f639b800; // add y^08 * (20! / 08!) z = (z * y) / FIXED_1; res += z * 0x00000618fee9f800; // add y^09 * (20! / 09!) z = (z * y) / FIXED_1; res += z * 0x0000009c197dcc00; // add y^10 * (20! / 10!) z = (z * y) / FIXED_1; res += z * 0x0000000e30dce400; // add y^11 * (20! / 11!) z = (z * y) / FIXED_1; res += z * 0x000000012ebd1300; // add y^12 * (20! / 12!) z = (z * y) / FIXED_1; res += z * 0x0000000017499f00; // add y^13 * (20! / 13!) z = (z * y) / FIXED_1; res += z * 0x0000000001a9d480; // add y^14 * (20! / 14!) z = (z * y) / FIXED_1; res += z * 0x00000000001c6380; // add y^15 * (20! / 15!) z = (z * y) / FIXED_1; res += z * 0x000000000001c638; // add y^16 * (20! / 16!) z = (z * y) / FIXED_1; res += z * 0x0000000000001ab8; // add y^17 * (20! / 17!) z = (z * y) / FIXED_1; res += z * 0x000000000000017c; // add y^18 * (20! / 18!) z = (z * y) / FIXED_1; res += z * 0x0000000000000014; // add y^19 * (20! / 19!) z = (z * y) / FIXED_1; res += z * 0x0000000000000001; // add y^20 * (20! / 20!) res = res / 0x21c3677c82b40000 + y + FIXED_1; // divide by 20! and then add y^1 / 1! + y^0 / 0! if ((x & 0x010000000000000000000000000000000) != 0) res = (res * 0x1c3d6a24ed82218787d624d3e5eba95f9) / 0x18ebef9eac820ae8682b9793ac6d1e776; // multiply by e^2^(-3) if ((x & 0x020000000000000000000000000000000) != 0) res = (res * 0x18ebef9eac820ae8682b9793ac6d1e778) / 0x1368b2fc6f9609fe7aceb46aa619baed4; // multiply by e^2^(-2) if ((x & 0x040000000000000000000000000000000) != 0) res = (res * 0x1368b2fc6f9609fe7aceb46aa619baed5) / 0x0bc5ab1b16779be3575bd8f0520a9f21f; // multiply by e^2^(-1) if ((x & 0x080000000000000000000000000000000) != 0) res = (res * 0x0bc5ab1b16779be3575bd8f0520a9f21e) / 0x0454aaa8efe072e7f6ddbab84b40a55c9; // multiply by e^2^(+0) if ((x & 0x100000000000000000000000000000000) != 0) res = (res * 0x0454aaa8efe072e7f6ddbab84b40a55c5) / 0x00960aadc109e7a3bf4578099615711ea; // multiply by e^2^(+1) if ((x & 0x200000000000000000000000000000000) != 0) res = (res * 0x00960aadc109e7a3bf4578099615711d7) / 0x0002bf84208204f5977f9a8cf01fdce3d; // multiply by e^2^(+2) if ((x & 0x400000000000000000000000000000000) != 0) res = (res * 0x0002bf84208204f5977f9a8cf01fdc307) / 0x0000003c6ab775dd0b95b4cbee7e65d11; // multiply by e^2^(+3) return res; } /** * @dev deprecated, backward compatibility */ function calculateCrossConnectorReturn( uint256 _fromConnectorBalance, uint32 _fromConnectorWeight, uint256 _toConnectorBalance, uint32 _toConnectorWeight, uint256 _amount ) public view returns (uint256) { return calculateCrossReserveReturn( _fromConnectorBalance, _fromConnectorWeight, _toConnectorBalance, _toConnectorWeight, _amount ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "./IGraphProxy.sol"; /** * @title Graph Upgradeable * @dev This contract is intended to be inherited from upgradeable contracts. */ contract GraphUpgradeable { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Check if the caller is the proxy admin. */ modifier onlyProxyAdmin(IGraphProxy _proxy) { require(msg.sender == _proxy.admin(), "Caller must be the proxy admin"); _; } /** * @dev Check if the caller is the implementation. */ modifier onlyImpl { require(msg.sender == _implementation(), "Caller must be the implementation"); _; } /** * @dev Returns the current implementation. * @return impl Address of the current implementation */ function _implementation() internal view returns (address impl) { bytes32 slot = IMPLEMENTATION_SLOT; assembly { impl := sload(slot) } } /** * @dev Accept to be an implementation of proxy. */ function acceptProxy(IGraphProxy _proxy) external onlyProxyAdmin(_proxy) { _proxy.acceptUpgrade(); } /** * @dev Accept to be an implementation of proxy and then call a function from the new * implementation as specified by `_data`, which should be an encoded function call. This is * useful to initialize new storage variables in the proxied contract. */ function acceptProxyAndCall(IGraphProxy _proxy, bytes calldata _data) external onlyProxyAdmin(_proxy) { _proxy.acceptUpgradeAndCall(_data); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "./ICuration.sol"; import "../governance/Managed.sol"; contract CurationV1Storage is Managed { // -- State -- // Tax charged when curator deposit funds // Parts per million. (Allows for 4 decimal points, 999,999 = 99.9999%) uint32 internal _curationTaxPercentage; // Default reserve ratio to configure curator shares bonding curve // Parts per million. (Allows for 4 decimal points, 999,999 = 99.9999%) uint32 public defaultReserveRatio; // Minimum amount allowed to be deposited by curators to initialize a pool // This is the `startPoolBalance` for the bonding curve uint256 public minimumCurationDeposit; // Bonding curve formula address public bondingCurve; // Mapping of subgraphDeploymentID => CurationPool // There is only one CurationPool per SubgraphDeploymentID mapping(bytes32 => ICuration.CurationPool) public pools; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "./IGraphCurationToken.sol"; interface ICuration { // -- Pool -- struct CurationPool { uint256 tokens; // GRT Tokens stored as reserves for the subgraph deployment uint32 reserveRatio; // Ratio for the bonding curve IGraphCurationToken gcs; // Curation token contract for this curation pool } // -- Configuration -- function setDefaultReserveRatio(uint32 _defaultReserveRatio) external; function setMinimumCurationDeposit(uint256 _minimumCurationDeposit) external; function setCurationTaxPercentage(uint32 _percentage) external; // -- Curation -- function mint( bytes32 _subgraphDeploymentID, uint256 _tokensIn, uint256 _signalOutMin ) external returns (uint256, uint256); function burn( bytes32 _subgraphDeploymentID, uint256 _signalIn, uint256 _tokensOutMin ) external returns (uint256); function collect(bytes32 _subgraphDeploymentID, uint256 _tokens) external; // -- Getters -- function isCurated(bytes32 _subgraphDeploymentID) external view returns (bool); function getCuratorSignal(address _curator, bytes32 _subgraphDeploymentID) external view returns (uint256); function getCurationPoolSignal(bytes32 _subgraphDeploymentID) external view returns (uint256); function getCurationPoolTokens(bytes32 _subgraphDeploymentID) external view returns (uint256); function tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn) external view returns (uint256, uint256); function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signalIn) external view returns (uint256); function curationTaxPercentage() external view returns (uint32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../governance/Governed.sol"; /** * @title GraphCurationToken contract * @dev This is the implementation of the Curation ERC20 token (GCS). * GCS are created for each subgraph deployment curated in the Curation contract. * The Curation contract is the owner of GCS tokens and the only one allowed to mint or * burn them. GCS tokens are transferrable and their holders can do any action allowed * in a standard ERC20 token implementation except for burning them. */ contract GraphCurationToken is ERC20, Governed { /** * @dev Graph Curation Token Contract Constructor. * @param _owner Address of the contract issuing this token */ constructor(address _owner) ERC20("Graph Curation Share", "GCS") { Governed._initialize(_owner); } /** * @dev Mint new tokens. * @param _to Address to send the newly minted tokens * @param _amount Amount of tokens to mint */ function mint(address _to, uint256 _amount) public onlyGovernor { _mint(_to, _amount); } /** * @dev Burn tokens from an address. * @param _account Address from where tokens will be burned * @param _amount Amount of tokens to burn */ function burnFrom(address _account, uint256 _amount) public onlyGovernor { _burn(_account, _amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; interface IGraphProxy { function admin() external returns (address); function setAdmin(address _newAdmin) external; function implementation() external returns (address); function pendingImplementation() external returns (address); function upgradeTo(address _newImplementation) external; function acceptUpgrade() external; function acceptUpgradeAndCall(bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "./IManaged.sol"; import "./IController.sol"; import "../curation/ICuration.sol"; import "../epochs/IEpochManager.sol"; import "../rewards/IRewardsManager.sol"; import "../staking/IStaking.sol"; import "../token/IGraphToken.sol"; /** * @title Graph Managed contract * @dev The Managed contract provides an interface for contracts to interact with the Controller * Inspired by Livepeer: * https://github.com/livepeer/protocol/blob/streamflow/contracts/Controller.sol */ contract Managed { // Controller that contract is registered with IController public controller; mapping(bytes32 => address) public addressCache; uint256[10] private __gap; event ParameterUpdated(string param); event SetController(address controller); function _notPartialPaused() internal view { require(!controller.paused(), "Paused"); require(!controller.partialPaused(), "Partial-paused"); } function _notPaused() internal view { require(!controller.paused(), "Paused"); } function _onlyGovernor() internal view { require(msg.sender == controller.getGovernor(), "Caller must be Controller governor"); } modifier notPartialPaused { _notPartialPaused(); _; } modifier notPaused { _notPaused(); _; } // Check if sender is controller modifier onlyController() { require(msg.sender == address(controller), "Caller must be Controller"); _; } modifier onlyGovernor() { _onlyGovernor(); _; } /** * @dev Initialize the controller */ function _initialize(address _controller) internal { _setController(_controller); } /** * @notice Set Controller. Only callable by current controller * @param _controller Controller contract address */ function setController(address _controller) external onlyController { _setController(_controller); } /** * @dev Set controller. * @param _controller Controller contract address */ function _setController(address _controller) internal { require(_controller != address(0), "Controller must be set"); controller = IController(_controller); emit SetController(_controller); } /** * @dev Return Curation interface * @return Curation contract registered with Controller */ function curation() internal view returns (ICuration) { return ICuration(controller.getContractProxy(keccak256("Curation"))); } /** * @dev Return EpochManager interface * @return Epoch manager contract registered with Controller */ function epochManager() internal view returns (IEpochManager) { return IEpochManager(controller.getContractProxy(keccak256("EpochManager"))); } /** * @dev Return RewardsManager interface * @return Rewards manager contract registered with Controller */ function rewardsManager() internal view returns (IRewardsManager) { return IRewardsManager(controller.getContractProxy(keccak256("RewardsManager"))); } /** * @dev Return Staking interface * @return Staking contract registered with Controller */ function staking() internal view returns (IStaking) { return IStaking(controller.getContractProxy(keccak256("Staking"))); } /** * @dev Return GraphToken interface * @return Graph token contract registered with Controller */ function graphToken() internal view returns (IGraphToken) { return IGraphToken(controller.getContractProxy(keccak256("GraphToken"))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IGraphCurationToken is IERC20 { function burnFrom(address _account, uint256 _amount) external; function mint(address _to, uint256 _amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; interface IManaged { function setController(address _controller) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12 <0.8.0; interface IController { function getGovernor() external view returns (address); // -- Registry -- function setContractProxy(bytes32 _id, address _contractAddress) external; function unsetContractProxy(bytes32 _id) external; function updateController(bytes32 _id, address _controller) external; function getContractProxy(bytes32 _id) external view returns (address); // -- Pausing -- function setPartialPaused(bool _partialPaused) external; function setPaused(bool _paused) external; function setPauseGuardian(address _newPauseGuardian) external; function paused() external view returns (bool); function partialPaused() external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; interface IEpochManager { // -- Configuration -- function setEpochLength(uint256 _epochLength) external; // -- Epochs function runEpoch() external; // -- Getters -- function isCurrentEpochRun() external view returns (bool); function blockNum() external view returns (uint256); function blockHash(uint256 _block) external view returns (bytes32); function currentEpoch() external view returns (uint256); function currentEpochBlock() external view returns (uint256); function currentEpochBlockSinceStart() external view returns (uint256); function epochsSince(uint256 _epoch) external view returns (uint256); function epochsSinceUpdate() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; interface IRewardsManager { /** * @dev Stores accumulated rewards and snapshots related to a particular SubgraphDeployment. */ struct Subgraph { uint256 accRewardsForSubgraph; uint256 accRewardsForSubgraphSnapshot; uint256 accRewardsPerSignalSnapshot; uint256 accRewardsPerAllocatedToken; } // -- Params -- function setIssuanceRate(uint256 _issuanceRate) external; // -- Denylist -- function setSubgraphAvailabilityOracle(address _subgraphAvailabilityOracle) external; function setDenied(bytes32 _subgraphDeploymentID, bool _deny) external; function setDeniedMany(bytes32[] calldata _subgraphDeploymentID, bool[] calldata _deny) external; function isDenied(bytes32 _subgraphDeploymentID) external view returns (bool); // -- Getters -- function getNewRewardsPerSignal() external view returns (uint256); function getAccRewardsPerSignal() external view returns (uint256); function getAccRewardsForSubgraph(bytes32 _subgraphDeploymentID) external view returns (uint256); function getAccRewardsPerAllocatedToken(bytes32 _subgraphDeploymentID) external view returns (uint256, uint256); function getRewards(address _allocationID) external view returns (uint256); // -- Updates -- function updateAccRewardsPerSignal() external returns (uint256); function takeRewards(address _allocationID) external returns (uint256); // -- Hooks -- function onSubgraphSignalUpdate(bytes32 _subgraphDeploymentID) external returns (uint256); function onSubgraphAllocationUpdate(bytes32 _subgraphDeploymentID) external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.12 <0.8.0; pragma experimental ABIEncoderV2; interface IStaking { // -- Allocation Data -- /** * @dev Possible states an allocation can be * States: * - Null = indexer == address(0) * - Active = not Null && tokens > 0 * - Closed = Active && closedAtEpoch != 0 * - Finalized = Closed && closedAtEpoch + channelDisputeEpochs > now() * - Claimed = not Null && tokens == 0 */ enum AllocationState { Null, Active, Closed, Finalized, Claimed } /** * @dev Allocate GRT tokens for the purpose of serving queries of a subgraph deployment * An allocation is created in the allocate() function and consumed in claim() */ struct Allocation { address indexer; bytes32 subgraphDeploymentID; uint256 tokens; // Tokens allocated to a SubgraphDeployment uint256 createdAtEpoch; // Epoch when it was created uint256 closedAtEpoch; // Epoch when it was closed uint256 collectedFees; // Collected fees for the allocation uint256 effectiveAllocation; // Effective allocation when closed uint256 accRewardsPerAllocatedToken; // Snapshot used for reward calc } /** * @dev Represents a request to close an allocation with a specific proof of indexing. * This is passed when calling closeAllocationMany to define the closing parameters for * each allocation. */ struct CloseAllocationRequest { address allocationID; bytes32 poi; } // -- Delegation Data -- /** * @dev Delegation pool information. One per indexer. */ struct DelegationPool { uint32 cooldownBlocks; // Blocks to wait before updating parameters uint32 indexingRewardCut; // in PPM uint32 queryFeeCut; // in PPM uint256 updatedAtBlock; // Block when the pool was last updated uint256 tokens; // Total tokens as pool reserves uint256 shares; // Total shares minted in the pool mapping(address => Delegation) delegators; // Mapping of delegator => Delegation } /** * @dev Individual delegation data of a delegator in a pool. */ struct Delegation { uint256 shares; // Shares owned by a delegator in the pool uint256 tokensLocked; // Tokens locked for undelegation uint256 tokensLockedUntil; // Block when locked tokens can be withdrawn } // -- Configuration -- function setMinimumIndexerStake(uint256 _minimumIndexerStake) external; function setThawingPeriod(uint32 _thawingPeriod) external; function setCurationPercentage(uint32 _percentage) external; function setProtocolPercentage(uint32 _percentage) external; function setChannelDisputeEpochs(uint32 _channelDisputeEpochs) external; function setMaxAllocationEpochs(uint32 _maxAllocationEpochs) external; function setRebateRatio(uint32 _alphaNumerator, uint32 _alphaDenominator) external; function setDelegationRatio(uint32 _delegationRatio) external; function setDelegationParameters( uint32 _indexingRewardCut, uint32 _queryFeeCut, uint32 _cooldownBlocks ) external; function setDelegationParametersCooldown(uint32 _blocks) external; function setDelegationUnbondingPeriod(uint32 _delegationUnbondingPeriod) external; function setDelegationTaxPercentage(uint32 _percentage) external; function setSlasher(address _slasher, bool _allowed) external; function setAssetHolder(address _assetHolder, bool _allowed) external; // -- Operation -- function setOperator(address _operator, bool _allowed) external; function isOperator(address _operator, address _indexer) external view returns (bool); // -- Staking -- function stake(uint256 _tokens) external; function stakeTo(address _indexer, uint256 _tokens) external; function unstake(uint256 _tokens) external; function slash( address _indexer, uint256 _tokens, uint256 _reward, address _beneficiary ) external; function withdraw() external; // -- Delegation -- function delegate(address _indexer, uint256 _tokens) external returns (uint256); function undelegate(address _indexer, uint256 _shares) external returns (uint256); function withdrawDelegated(address _indexer, address _newIndexer) external returns (uint256); // -- Channel management and allocations -- function allocate( bytes32 _subgraphDeploymentID, uint256 _tokens, address _allocationID, bytes32 _metadata, bytes calldata _proof ) external; function allocateFrom( address _indexer, bytes32 _subgraphDeploymentID, uint256 _tokens, address _allocationID, bytes32 _metadata, bytes calldata _proof ) external; function closeAllocation(address _allocationID, bytes32 _poi) external; function closeAllocationMany(CloseAllocationRequest[] calldata _requests) external; function closeAndAllocate( address _oldAllocationID, bytes32 _poi, address _indexer, bytes32 _subgraphDeploymentID, uint256 _tokens, address _allocationID, bytes32 _metadata, bytes calldata _proof ) external; function collect(uint256 _tokens, address _allocationID) external; function claim(address _allocationID, bool _restake) external; function claimMany(address[] calldata _allocationID, bool _restake) external; // -- Getters and calculations -- function hasStake(address _indexer) external view returns (bool); function getIndexerStakedTokens(address _indexer) external view returns (uint256); function getIndexerCapacity(address _indexer) external view returns (uint256); function getAllocation(address _allocationID) external view returns (Allocation memory); function getAllocationState(address _allocationID) external view returns (AllocationState); function isAllocation(address _allocationID) external view returns (bool); function getSubgraphAllocatedTokens(bytes32 _subgraphDeploymentID) external view returns (uint256); function getDelegation(address _indexer, address _delegator) external view returns (Delegation memory); function isDelegator(address _indexer, address _delegator) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IGraphToken is IERC20 { // -- Mint and Burn -- function burn(uint256 amount) external; function mint(address _to, uint256 _amount) external; // -- Mint Admin -- function addMinter(address _account) external; function removeMinter(address _account) external; function renounceMinter() external; function isMinter(address _account) external view returns (bool); // -- Permit -- function permit( address _owner, address _spender, uint256 _value, uint256 _deadline, uint8 _v, bytes32 _r, bytes32 _s ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../../GSN/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * 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 returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(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) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.3; /** * @title Graph Governance contract * @dev All contracts that will be owned by a Governor entity should extend this contract. */ contract Governed { // -- State -- address public governor; address public pendingGovernor; // -- Events -- event NewPendingOwnership(address indexed from, address indexed to); event NewOwnership(address indexed from, address indexed to); /** * @dev Check if the caller is the governor. */ modifier onlyGovernor { require(msg.sender == governor, "Only Governor can call"); _; } /** * @dev Initialize the governor to the contract caller. */ function _initialize(address _initGovernor) internal { governor = _initGovernor; } /** * @dev Admin function to begin change of governor. The `_newGovernor` must call * `acceptOwnership` to finalize the transfer. * @param _newGovernor Address of new `governor` */ function transferOwnership(address _newGovernor) external onlyGovernor { require(_newGovernor != address(0), "Governor must be set"); address oldPendingGovernor = pendingGovernor; pendingGovernor = _newGovernor; emit NewPendingOwnership(oldPendingGovernor, pendingGovernor); } /** * @dev Admin function for pending governor to accept role and update governor. * This function must called by the pending governor. */ function acceptOwnership() external { require( pendingGovernor != address(0) && msg.sender == pendingGovernor, "Caller must be pending governor" ); address oldGovernor = governor; address oldPendingGovernor = pendingGovernor; governor = pendingGovernor; pendingGovernor = address(0); emit NewOwnership(oldGovernor, governor); emit NewPendingOwnership(oldPendingGovernor, pendingGovernor); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"curator","type":"address"},{"indexed":true,"internalType":"bytes32","name":"subgraphDeploymentID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"signal","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"subgraphDeploymentID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"}],"name":"Collected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"param","type":"string"}],"name":"ParameterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"controller","type":"address"}],"name":"SetController","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"curator","type":"address"},{"indexed":true,"internalType":"bytes32","name":"subgraphDeploymentID","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"tokens","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"signal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"curationTax","type":"uint256"}],"name":"Signalled","type":"event"},{"inputs":[{"internalType":"contract IGraphProxy","name":"_proxy","type":"address"}],"name":"acceptProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IGraphProxy","name":"_proxy","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"acceptProxyAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"addressCache","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondingCurve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_signalIn","type":"uint256"},{"internalType":"uint256","name":"_tokensOutMin","type":"uint256"}],"name":"burn","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_tokens","type":"uint256"}],"name":"collect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"curationTaxPercentage","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultReserveRatio","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"getCurationPoolSignal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"getCurationPoolTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curator","type":"address"},{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"getCuratorSignal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_bondingCurve","type":"address"},{"internalType":"uint32","name":"_defaultReserveRatio","type":"uint32"},{"internalType":"uint32","name":"_curationTaxPercentage","type":"uint32"},{"internalType":"uint256","name":"_minimumCurationDeposit","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"}],"name":"isCurated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumCurationDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_tokensIn","type":"uint256"},{"internalType":"uint256","name":"_signalOutMin","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"pools","outputs":[{"internalType":"uint256","name":"tokens","type":"uint256"},{"internalType":"uint32","name":"reserveRatio","type":"uint32"},{"internalType":"contract IGraphCurationToken","name":"gcs","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_percentage","type":"uint32"}],"name":"setCurationTaxPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_defaultReserveRatio","type":"uint32"}],"name":"setDefaultReserveRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minimumCurationDeposit","type":"uint256"}],"name":"setMinimumCurationDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_signalIn","type":"uint256"}],"name":"signalToTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_subgraphDeploymentID","type":"bytes32"},{"internalType":"uint256","name":"_tokensIn","type":"uint256"}],"name":"tokensToSignal","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506136c0806100206000396000f3fe60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80639ce7abe511620000d5578063dc675a651162000087578063dc675a6514620004cc578063eba0c8a11462000508578063eff1d50e146200052b578063f049b9001462000535578063f115c427146200055b578063f77c47911462000565576200016c565b80639ce7abe514620003585780639f94c66714620003dc578063a2594d82146200040b578063b5217bb41462000434578063cd0ad4a21462000480578063cd18119e14620004a6576200016c565b80634c4ea0ed116200012f5780634c4ea0ed14620002445780636536fe32146200027857806381573288146200029a57806392eefe9b14620002c057806399439fee14620002e95780639ae3824c1462000309576200016c565b80630faaf87f1462000171578063185360f914620001a957806324bdeec714620001b3578063375a54ab14620001df57806346e855da1462000224575b600080fd5b62000197600480360360408110156200018957600080fd5b50803590602001356200056f565b60408051918252519081900360200190f35b62000197620006f6565b6200019760048036036060811015620001cb57600080fd5b5080359060208101359060400135620006fc565b6200020b60048036036060811015620001f757600080fd5b508035906020810135906040013562000a0e565b6040805192835260208301919091528051918290030190f35b62000197600480360360208110156200023c57600080fd5b503562000dc2565b62000264600480360360208110156200025c57600080fd5b503562000dd7565b604080519115158252519081900360200190f35b62000298600480360360208110156200029057600080fd5b503562000deb565b005b6200029860048036036040811015620002b257600080fd5b508035906020013562000e03565b6200029860048036036020811015620002d857600080fd5b50356001600160a01b031662000eff565b62000197600480360360208110156200030157600080fd5b503562000f6a565b62000298600480360360a08110156200032157600080fd5b506001600160a01b03813581169160208101359091169063ffffffff60408201358116916060810135909116906080013562001031565b62000298600480360360408110156200037057600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156200039b57600080fd5b820183602082011115620003ae57600080fd5b803590602001918460018302840111600160201b83111715620003d057600080fd5b50909250905062001136565b6200019760048036036040811015620003f457600080fd5b506001600160a01b03813516906020013562001292565b62000298600480360360208110156200042357600080fd5b50356001600160a01b03166200135a565b62000454600480360360208110156200044c57600080fd5b50356200147b565b6040805193845263ffffffff90921660208401526001600160a01b031682820152519081900360600190f35b62000298600480360360208110156200049857600080fd5b503563ffffffff16620014ac565b6200029860048036036020811015620004be57600080fd5b503563ffffffff16620014c1565b620004ec60048036036020811015620004e457600080fd5b5035620014d6565b604080516001600160a01b039092168252519081900360200190f35b62000512620014f1565b6040805163ffffffff9092168252519081900360200190f35b620004ec62001504565b6200020b600480360360408110156200054d57600080fd5b508035906020013562001513565b620005126200156c565b620004ec62001578565b60006200057b6200217d565b506000838152600f6020908152604080832081516060810183528154815260019091015463ffffffff811693820193909352600160201b9092046001600160a01b03169082015290620005ce8562000f6a565b8251909150620006105760405162461bcd60e51b815260040180806020018281038252603b815260200180620034f7603b913960400191505060405180910390fd5b83811015620006515760405162461bcd60e51b8152600401808060200182810382526043815260200180620034b46043913960600191505060405180910390fd5b600e548251602080850151604080516349f9b0f760e01b815260048101879052602481019490945263ffffffff909116604484015260648301889052516001600160a01b03909316926349f9b0f7926084808201939291829003018186803b158015620006bd57600080fd5b505afa158015620006d2573d6000803e3d6000fd5b505050506040513d6020811015620006e957600080fd5b5051925050505b92915050565b600d5481565b60006200070862001587565b33836200075c576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74206275726e207a65726f207369676e616c000000000000000000604482015290519081900360640190fd5b8362000769828762001292565b1015620007a85760405162461bcd60e51b8152600401808060200182810382526024815260200180620034906024913960400191505060405180910390fd5b6000620007b686866200056f565b90508381101562000804576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6200080f86620016ff565b6000868152600f6020526040902080546200082b908362001797565b815560018101546040805163079cc67960e41b81526001600160a01b038681166004830152602482018a90529151600160201b909304909116916379cc67909160448082019260009290919082900301818387803b1580156200088d57600080fd5b505af1158015620008a2573d6000803e3d6000fd5b50505050620008b18762000f6a565b620008d9576000878152600f6020526040812090815560010180546001600160c01b03191690555b620008e3620017e2565b6001600160a01b031663a9059cbb84846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156200093a57600080fd5b505af11580156200094f573d6000803e3d6000fd5b505050506040513d60208110156200096657600080fd5b5051620009ba576040805162461bcd60e51b815260206004820152601c60248201527f4572726f722073656e64696e672063757261746f7220746f6b656e7300000000604482015290519081900360640190fd5b86836001600160a01b03167fe14cd5e80f6821ded0538e85a537487acf10bb5e97a12176df56a099e90bfb348489604051808381526020018281526020019250505060405180910390a35095945050505050565b60008062000a1b62001587565b6000841162000a71576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f74206465706f736974207a65726f20746f6b656e73000000000000604482015290519081900360640190fd5b60008062000a80878762001513565b915091508482101562000ad0576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6000878152600f60205260409020339062000aeb8962000dd7565b62000b8a57600c5460018201805463ffffffff191663ffffffff600160201b93849004161790819055046001600160a01b031662000b8a573060405162000b32906200219d565b6001600160a01b03909116815260405190819003602001906000f08015801562000b60573d6000803e3d6000fd5b508160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055505b62000b9589620016ff565b600062000ba1620017e2565b604080516323b872dd60e01b81526001600160a01b038681166004830152306024830152604482018d90529151929350908316916323b872dd916064808201926020929091908290030181600087803b15801562000bfe57600080fd5b505af115801562000c13573d6000803e3d6000fd5b505050506040513d602081101562000c2a57600080fd5b505162000c695760405162461bcd60e51b81526004018080602001828103825260218152602001806200366a6021913960400191505060405180910390fd5b831562000cd157806001600160a01b03166342966c68856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801562000cb757600080fd5b505af115801562000ccc573d6000803e3d6000fd5b505050505b62000cea62000ce18a8662001797565b83549062001882565b82556001820154604080516340c10f1960e01b81526001600160a01b038681166004830152602482018990529151600160201b909304909116916340c10f199160448082019260009290919082900301818387803b15801562000d4c57600080fd5b505af115801562000d61573d6000803e3d6000fd5b5050604080518c81526020810189905280820188905290518d93506001600160a01b03871692507fb7bf5f4e5b23ef992df9875ecea572620d18dab0c1a5486a9b695d20d9ec50cf9181900360600190a35092989197509095505050505050565b6000818152600f60205260409020545b919050565b6000908152600f6020526040902054151590565b62000df5620018dd565b62000e0081620019a0565b50565b62000e0d62001a42565b6001600160a01b0316336001600160a01b03161462000e5e5760405162461bcd60e51b8152600401808060200182810382526023815260200180620035ed6023913960400191505060405180910390fd5b62000e698262000dd7565b62000ea65760405162461bcd60e51b81526004018080602001828103825260338152602001806200345d6033913960400191505060405180910390fd5b6000828152600f60205260409020805462000ec2908362001882565b815560408051838152905184917ff17fdee613a92b35db6b7598eb43750b24d4072eb304e6eca80121e40402e34b919081900360200190a2505050565b6000546001600160a01b0316331462000f5f576040805162461bcd60e51b815260206004820152601960248201527f43616c6c6572206d75737420626520436f6e74726f6c6c657200000000000000604482015290519081900360640190fd5b62000e008162001aaf565b6000818152600f6020526040812060010154600160201b90046001600160a01b031662000f9a5750600062000dd2565b600f600083815260200190815260200160002060010160049054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000ffd57600080fd5b505afa15801562001012573d6000803e3d6000fd5b505050506040513d60208110156200102957600080fd5b505192915050565b6200103b62001b58565b6001600160a01b0316336001600160a01b0316146200108c5760405162461bcd60e51b8152600401808060200182810382526021815260200180620036496021913960400191505060405180910390fd5b620010978562000f5f565b6001600160a01b038416620010f3576040805162461bcd60e51b815260206004820152601960248201527f426f6e64696e67206375727665206d7573742062652073657400000000000000604482015290519081900360640190fd5b600e80546001600160a01b0319166001600160a01b038616179055620011198362001b7d565b620011248262001c87565b6200112f81620019a0565b5050505050565b82806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200117357600080fd5b505af115801562001188573d6000803e3d6000fd5b505050506040513d60208110156200119f57600080fd5b50516001600160a01b03163314620011fe576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b60405163623faf6160e01b8152602060048201908152602482018490526001600160a01b0386169163623faf619186918691908190604401848480828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b1580156200127357600080fd5b505af115801562001288573d6000803e3d6000fd5b5050505050505050565b6000818152600f6020526040812060010154600160201b90046001600160a01b0316620012c257506000620006f0565b6000828152600f60209081526040918290206001015482516370a0823160e01b81526001600160a01b0387811660048301529351600160201b909204909316926370a08231926024808301939192829003018186803b1580156200132557600080fd5b505afa1580156200133a573d6000803e3d6000fd5b505050506040513d60208110156200135157600080fd5b50519392505050565b80806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200139757600080fd5b505af1158015620013ac573d6000803e3d6000fd5b505050506040513d6020811015620013c357600080fd5b50516001600160a01b0316331462001422576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b816001600160a01b03166359fc20bb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200145e57600080fd5b505af115801562001473573d6000803e3d6000fd5b505050505050565b600f602052600090815260409020805460019091015463ffffffff811690600160201b90046001600160a01b031683565b620014b6620018dd565b62000e008162001b7d565b620014cb620018dd565b62000e008162001c87565b6001602052600090815260409020546001600160a01b031681565b600c54600160201b900463ffffffff1681565b600e546001600160a01b031681565b600c54600090819081906200154590620f4240906200153e90879063ffffffff9081169062001d4216565b9062001da0565b9050600062001560866200155a878562001797565b62001de4565b96919550909350505050565b600c5463ffffffff1690565b6000546001600160a01b031681565b60008054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015620015d457600080fd5b505afa158015620015e9573d6000803e3d6000fd5b505050506040513d60208110156200160057600080fd5b5051156200163e576040805162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316632e292fc76040518163ffffffff1660e01b815260040160206040518083038186803b1580156200168b57600080fd5b505afa158015620016a0573d6000803e3d6000fd5b505050506040513d6020811015620016b757600080fd5b505115620016fd576040805162461bcd60e51b815260206004820152600e60248201526d14185c9d1a585b0b5c185d5cd95960921b604482015290519081900360640190fd5b565b60006200170b6200200c565b90506001600160a01b038116156200179357806001600160a01b0316631d1c2fec836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156200176457600080fd5b505af115801562001779573d6000803e3d6000fd5b505050506040513d60208110156200179057600080fd5b50505b5050565b6000620017db83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525062002079565b9392505050565b6000805460408051637bb20d2f60e11b81527f45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b505afa15801562001864573d6000803e3d6000fd5b505050506040513d60208110156200187b57600080fd5b5051905090565b600082820183811015620017db576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316634fc07d756040518163ffffffff1660e01b815260040160206040518083038186803b1580156200192a57600080fd5b505afa1580156200193f573d6000803e3d6000fd5b505050506040513d60208110156200195657600080fd5b50516001600160a01b03163314620016fd5760405162461bcd60e51b8152600401808060200182810382526022815260200180620035776022913960400191505060405180910390fd5b60008111620019e15760405162461bcd60e51b8152600401808060200182810382526024815260200180620035326024913960400191505060405180910390fd5b600d819055604080516020808252601690820152751b5a5b9a5b5d5b50dd5c985d1a5bdb91195c1bdcda5d60521b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c9181900360600190a150565b6000805460408051637bb20d2f60e11b81527f1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d167034600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b6001600160a01b03811662001b04576040805162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9bdb1b195c881b5d5cdd081899481cd95d60521b604482015290519081900360640190fd5b600080546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f4ff638452bbf33c012645d18ae6f05515ff5f2d1dfb0cece8cbf018c60903f709181900360200190a150565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b60008163ffffffff161162001bc45760405162461bcd60e51b8152600401808060200182810382526021815260200180620035996021913960400191505060405180910390fd5b620f424063ffffffff8216111562001c0e5760405162461bcd60e51b8152600401808060200182810382526033815260200180620035ba6033913960400191505060405180910390fd5b600c805467ffffffff000000001916600160201b63ffffffff8416021790556040805160208082526013908201527264656661756c7452657365727665526174696f60681b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b620f424063ffffffff8216111562001cd15760405162461bcd60e51b8152600401808060200182810382526039815260200180620036106039913960400191505060405180910390fd5b600c805463ffffffff191663ffffffff8316179055604080516020808252601590820152746375726174696f6e54617850657263656e7461676560581b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b60008262001d5357506000620006f0565b8282028284828162001d6157fe5b0414620017db5760405162461bcd60e51b8152600401808060200182810382526021815260200180620035566021913960400191505060405180910390fd5b6000620017db83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525062002114565b600062001df06200217d565b506000838152600f60209081526040918290208251606081018452815480825260019092015463ffffffff811693820193909352600160201b9092046001600160a01b0316928201929092529062001f5f57600d5483101562001e855760405162461bcd60e51b815260040180806020018281038252602a81526020018062003433602a913960400191505060405180910390fd5b600e54600d54600c5462001f5692670de0b6b3a7640000926001600160a01b03909116916329a00e7c91849163ffffffff600160201b90910481169062001ed1908b9084906200179716565b6040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001f2157600080fd5b505afa15801562001f36573d6000803e3d6000fd5b505050506040513d602081101562001f4d57600080fd5b50519062001882565b915050620006f0565b600e546001600160a01b03166329a00e7c62001f7b8662000f6a565b83600001518460200151876040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001fd657600080fd5b505afa15801562001feb573d6000803e3d6000fd5b505050506040513d60208110156200200257600080fd5b5051949350505050565b6000805460408051637bb20d2f60e11b81527f966f1e8d8d8014e05f6ec4a57138da9be1f7c5a7f802928a18072f7c53180761600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b600081848411156200210c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620020d0578181015183820152602001620020b6565b50505050905090810190601f168015620020fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183620021665760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620020d0578181015183820152602001620020b6565b5060008385816200217357fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b61128780620021ac8339019056fe60806040523480156200001157600080fd5b506040516200128738038062001287833981810160405260208110156200003757600080fd5b5051604080518082018252601481527f4772617068204375726174696f6e2053686172650000000000000000000000006020828101918252835180850190945260038085526247435360e81b9185019190915282519293926200009b929062000109565b508051620000b190600490602084019062000109565b505060058054601260ff1990911617905550620000da81620000e1602090811b620009aa17901c565b50620001b5565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826200014157600085556200018c565b82601f106200015c57805160ff19168380011785556200018c565b828001600101855582156200018c579182015b828111156200018c5782518255916020019190600101906200016f565b506200019a9291506200019e565b5090565b5b808211156200019a57600081556001016200019f565b6110c280620001c56000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806370a08231116100a2578063a457c2d711610071578063a457c2d71461031b578063a9059cbb14610347578063dd62ed3e14610373578063e3056a34146103a1578063f2fde38b146103a95761010b565b806370a08231146102b957806379ba5097146102df57806379cc6790146102e757806395d89b41146103135761010b565b806323b872dd116100de57806323b872dd1461020b578063313ce56714610241578063395093511461025f57806340c10f191461028b5761010b565b806306fdde0314610110578063095ea7b31461018d5780630c340a24146101cd57806318160ddd146101f1575b600080fd5b6101186103cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561015257818101518382015260200161013a565b50505050905090810190601f16801561017f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b9600480360360408110156101a357600080fd5b506001600160a01b038135169060200135610465565b604080519115158252519081900360200190f35b6101d5610482565b604080516001600160a01b039092168252519081900360200190f35b6101f9610496565b60408051918252519081900360200190f35b6101b96004803603606081101561022157600080fd5b506001600160a01b0381358116916020810135909116906040013561049c565b610249610523565b6040805160ff9092168252519081900360200190f35b6101b96004803603604081101561027557600080fd5b506001600160a01b03813516906020013561052c565b6102b7600480360360408110156102a157600080fd5b506001600160a01b03813516906020013561057a565b005b6101f9600480360360208110156102cf57600080fd5b50356001600160a01b03166105e5565b6102b7610600565b6102b7600480360360408110156102fd57600080fd5b506001600160a01b038135169060200135610729565b610118610790565b6101b96004803603604081101561033157600080fd5b506001600160a01b0381351690602001356107f1565b6101b96004803603604081101561035d57600080fd5b506001600160a01b038135169060200135610859565b6101f96004803603604081101561038957600080fd5b506001600160a01b038135811691602001351661086d565b6101d5610898565b6102b7600480360360208110156103bf57600080fd5b50356001600160a01b03166108a7565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b820191906000526020600020905b81548152906001019060200180831161043e57829003601f168201915b5050505050905090565b60006104796104726109d2565b84846109d6565b50600192915050565b60055461010090046001600160a01b031681565b60025490565b60006104a9848484610ac2565b610519846104b56109d2565b61051485604051806060016040528060288152602001610fd6602891396001600160a01b038a166000908152600160205260408120906104f36109d2565b6001600160a01b031681526020810191909152604001600020549190610c1d565b6109d6565b5060019392505050565b60055460ff1690565b60006104796105396109d2565b84610514856001600061054a6109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610cb4565b60055461010090046001600160a01b031633146105d7576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610d15565b5050565b6001600160a01b031660009081526020819052604090205490565b6006546001600160a01b03161580159061062457506006546001600160a01b031633145b610675576040805162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f7200604482015290519081900360640190fd5b60058054600680546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b0319909316909355604051938290048116949293919092049091169083907f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f90600090a36006546040516001600160a01b03918216918316907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b60055461010090046001600160a01b03163314610786576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610e05565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b60006104796107fe6109d2565b846105148560405180606001604052806025815260200161106860259139600160006108286109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610c1d565b60006104796108666109d2565b8484610ac2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6006546001600160a01b031681565b60055461010090046001600160a01b03163314610904576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b038116610956576040805162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b604482015290519081900360640190fd5b600680546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b3390565b6001600160a01b038316610a1b5760405162461bcd60e51b81526004018080602001828103825260248152602001806110446024913960400191505060405180910390fd5b6001600160a01b038216610a605760405162461bcd60e51b8152600401808060200182810382526022815260200180610f8e6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316610b075760405162461bcd60e51b815260040180806020018281038252602581526020018061101f6025913960400191505060405180910390fd5b6001600160a01b038216610b4c5760405162461bcd60e51b8152600401808060200182810382526023815260200180610f496023913960400191505060405180910390fd5b610b57838383610f01565b610b9481604051806060016040528060268152602001610fb0602691396001600160a01b0386166000908152602081905260409020549190610c1d565b6001600160a01b038085166000908152602081905260408082209390935590841681522054610bc39082610cb4565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115610cac5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c71578181015183820152602001610c59565b50505050905090810190601f168015610c9e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610d0e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216610d70576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610d7c60008383610f01565b600254610d899082610cb4565b6002556001600160a01b038216600090815260208190526040902054610daf9082610cb4565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610e4a5760405162461bcd60e51b8152600401808060200182810382526021815260200180610ffe6021913960400191505060405180910390fd5b610e5682600083610f01565b610e9381604051806060016040528060228152602001610f6c602291396001600160a01b0385166000908152602081905260409020549190610c1d565b6001600160a01b038316600090815260208190526040902055600254610eb99082610f06565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b505050565b6000610d0e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610c1d56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212204cb1015622950d635ba48cf5ee6af298ab114e15b9265ae471beca741183788564736f6c634300070400334375726174696f6e206465706f7369742069732062656c6f77206d696e696d756d2072657175697265645375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20636f6c6c656374206665657343616e6e6f74206275726e206d6f7265207369676e616c207468616e20796f75206f776e5369676e616c206d7573742062652061626f7665206f7220657175616c20746f207369676e616c2069737375656420696e20746865206375726174696f6e20706f6f6c5375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20706572666f726d2063616c63756c6174696f6e734d696e696d756d206375726174696f6e206465706f7369742063616e6e6f742062652030536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616c6c6572206d75737420626520436f6e74726f6c6c657220676f7665726e6f7244656661756c74207265736572766520726174696f206d757374206265203e203044656661756c74207265736572766520726174696f2063616e6e6f7420626520686967686572207468616e204d41585f50504d43616c6c6572206d75737420626520746865207374616b696e6720636f6e74726163744375726174696f6e207461782070657263656e74616765206d7573742062652062656c6f77206f7220657175616c20746f204d41585f50504d43616c6c6572206d7573742062652074686520696d706c656d656e746174696f6e43616e6e6f74207472616e7366657220746f6b656e7320746f206465706f736974a26469706673582212206264c30885d86e62b7838b4a997d40aae88812e93904b3faf9131cf287eaf3de64736f6c63430007040033
Deployed Bytecode
0x60806040523480156200001157600080fd5b50600436106200016c5760003560e01c80639ce7abe511620000d5578063dc675a651162000087578063dc675a6514620004cc578063eba0c8a11462000508578063eff1d50e146200052b578063f049b9001462000535578063f115c427146200055b578063f77c47911462000565576200016c565b80639ce7abe514620003585780639f94c66714620003dc578063a2594d82146200040b578063b5217bb41462000434578063cd0ad4a21462000480578063cd18119e14620004a6576200016c565b80634c4ea0ed116200012f5780634c4ea0ed14620002445780636536fe32146200027857806381573288146200029a57806392eefe9b14620002c057806399439fee14620002e95780639ae3824c1462000309576200016c565b80630faaf87f1462000171578063185360f914620001a957806324bdeec714620001b3578063375a54ab14620001df57806346e855da1462000224575b600080fd5b62000197600480360360408110156200018957600080fd5b50803590602001356200056f565b60408051918252519081900360200190f35b62000197620006f6565b6200019760048036036060811015620001cb57600080fd5b5080359060208101359060400135620006fc565b6200020b60048036036060811015620001f757600080fd5b508035906020810135906040013562000a0e565b6040805192835260208301919091528051918290030190f35b62000197600480360360208110156200023c57600080fd5b503562000dc2565b62000264600480360360208110156200025c57600080fd5b503562000dd7565b604080519115158252519081900360200190f35b62000298600480360360208110156200029057600080fd5b503562000deb565b005b6200029860048036036040811015620002b257600080fd5b508035906020013562000e03565b6200029860048036036020811015620002d857600080fd5b50356001600160a01b031662000eff565b62000197600480360360208110156200030157600080fd5b503562000f6a565b62000298600480360360a08110156200032157600080fd5b506001600160a01b03813581169160208101359091169063ffffffff60408201358116916060810135909116906080013562001031565b62000298600480360360408110156200037057600080fd5b6001600160a01b038235169190810190604081016020820135600160201b8111156200039b57600080fd5b820183602082011115620003ae57600080fd5b803590602001918460018302840111600160201b83111715620003d057600080fd5b50909250905062001136565b6200019760048036036040811015620003f457600080fd5b506001600160a01b03813516906020013562001292565b62000298600480360360208110156200042357600080fd5b50356001600160a01b03166200135a565b62000454600480360360208110156200044c57600080fd5b50356200147b565b6040805193845263ffffffff90921660208401526001600160a01b031682820152519081900360600190f35b62000298600480360360208110156200049857600080fd5b503563ffffffff16620014ac565b6200029860048036036020811015620004be57600080fd5b503563ffffffff16620014c1565b620004ec60048036036020811015620004e457600080fd5b5035620014d6565b604080516001600160a01b039092168252519081900360200190f35b62000512620014f1565b6040805163ffffffff9092168252519081900360200190f35b620004ec62001504565b6200020b600480360360408110156200054d57600080fd5b508035906020013562001513565b620005126200156c565b620004ec62001578565b60006200057b6200217d565b506000838152600f6020908152604080832081516060810183528154815260019091015463ffffffff811693820193909352600160201b9092046001600160a01b03169082015290620005ce8562000f6a565b8251909150620006105760405162461bcd60e51b815260040180806020018281038252603b815260200180620034f7603b913960400191505060405180910390fd5b83811015620006515760405162461bcd60e51b8152600401808060200182810382526043815260200180620034b46043913960600191505060405180910390fd5b600e548251602080850151604080516349f9b0f760e01b815260048101879052602481019490945263ffffffff909116604484015260648301889052516001600160a01b03909316926349f9b0f7926084808201939291829003018186803b158015620006bd57600080fd5b505afa158015620006d2573d6000803e3d6000fd5b505050506040513d6020811015620006e957600080fd5b5051925050505b92915050565b600d5481565b60006200070862001587565b33836200075c576040805162461bcd60e51b815260206004820152601760248201527f43616e6e6f74206275726e207a65726f207369676e616c000000000000000000604482015290519081900360640190fd5b8362000769828762001292565b1015620007a85760405162461bcd60e51b8152600401808060200182810382526024815260200180620034906024913960400191505060405180910390fd5b6000620007b686866200056f565b90508381101562000804576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6200080f86620016ff565b6000868152600f6020526040902080546200082b908362001797565b815560018101546040805163079cc67960e41b81526001600160a01b038681166004830152602482018a90529151600160201b909304909116916379cc67909160448082019260009290919082900301818387803b1580156200088d57600080fd5b505af1158015620008a2573d6000803e3d6000fd5b50505050620008b18762000f6a565b620008d9576000878152600f6020526040812090815560010180546001600160c01b03191690555b620008e3620017e2565b6001600160a01b031663a9059cbb84846040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050602060405180830381600087803b1580156200093a57600080fd5b505af11580156200094f573d6000803e3d6000fd5b505050506040513d60208110156200096657600080fd5b5051620009ba576040805162461bcd60e51b815260206004820152601c60248201527f4572726f722073656e64696e672063757261746f7220746f6b656e7300000000604482015290519081900360640190fd5b86836001600160a01b03167fe14cd5e80f6821ded0538e85a537487acf10bb5e97a12176df56a099e90bfb348489604051808381526020018281526020019250505060405180910390a35095945050505050565b60008062000a1b62001587565b6000841162000a71576040805162461bcd60e51b815260206004820152601a60248201527f43616e6e6f74206465706f736974207a65726f20746f6b656e73000000000000604482015290519081900360640190fd5b60008062000a80878762001513565b915091508482101562000ad0576040805162461bcd60e51b815260206004820152601360248201527229b634b83830b3b290383937ba32b1ba34b7b760691b604482015290519081900360640190fd5b6000878152600f60205260409020339062000aeb8962000dd7565b62000b8a57600c5460018201805463ffffffff191663ffffffff600160201b93849004161790819055046001600160a01b031662000b8a573060405162000b32906200219d565b6001600160a01b03909116815260405190819003602001906000f08015801562000b60573d6000803e3d6000fd5b508160010160046101000a8154816001600160a01b0302191690836001600160a01b031602179055505b62000b9589620016ff565b600062000ba1620017e2565b604080516323b872dd60e01b81526001600160a01b038681166004830152306024830152604482018d90529151929350908316916323b872dd916064808201926020929091908290030181600087803b15801562000bfe57600080fd5b505af115801562000c13573d6000803e3d6000fd5b505050506040513d602081101562000c2a57600080fd5b505162000c695760405162461bcd60e51b81526004018080602001828103825260218152602001806200366a6021913960400191505060405180910390fd5b831562000cd157806001600160a01b03166342966c68856040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801562000cb757600080fd5b505af115801562000ccc573d6000803e3d6000fd5b505050505b62000cea62000ce18a8662001797565b83549062001882565b82556001820154604080516340c10f1960e01b81526001600160a01b038681166004830152602482018990529151600160201b909304909116916340c10f199160448082019260009290919082900301818387803b15801562000d4c57600080fd5b505af115801562000d61573d6000803e3d6000fd5b5050604080518c81526020810189905280820188905290518d93506001600160a01b03871692507fb7bf5f4e5b23ef992df9875ecea572620d18dab0c1a5486a9b695d20d9ec50cf9181900360600190a35092989197509095505050505050565b6000818152600f60205260409020545b919050565b6000908152600f6020526040902054151590565b62000df5620018dd565b62000e0081620019a0565b50565b62000e0d62001a42565b6001600160a01b0316336001600160a01b03161462000e5e5760405162461bcd60e51b8152600401808060200182810382526023815260200180620035ed6023913960400191505060405180910390fd5b62000e698262000dd7565b62000ea65760405162461bcd60e51b81526004018080602001828103825260338152602001806200345d6033913960400191505060405180910390fd5b6000828152600f60205260409020805462000ec2908362001882565b815560408051838152905184917ff17fdee613a92b35db6b7598eb43750b24d4072eb304e6eca80121e40402e34b919081900360200190a2505050565b6000546001600160a01b0316331462000f5f576040805162461bcd60e51b815260206004820152601960248201527f43616c6c6572206d75737420626520436f6e74726f6c6c657200000000000000604482015290519081900360640190fd5b62000e008162001aaf565b6000818152600f6020526040812060010154600160201b90046001600160a01b031662000f9a5750600062000dd2565b600f600083815260200190815260200160002060010160049054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801562000ffd57600080fd5b505afa15801562001012573d6000803e3d6000fd5b505050506040513d60208110156200102957600080fd5b505192915050565b6200103b62001b58565b6001600160a01b0316336001600160a01b0316146200108c5760405162461bcd60e51b8152600401808060200182810382526021815260200180620036496021913960400191505060405180910390fd5b620010978562000f5f565b6001600160a01b038416620010f3576040805162461bcd60e51b815260206004820152601960248201527f426f6e64696e67206375727665206d7573742062652073657400000000000000604482015290519081900360640190fd5b600e80546001600160a01b0319166001600160a01b038616179055620011198362001b7d565b620011248262001c87565b6200112f81620019a0565b5050505050565b82806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200117357600080fd5b505af115801562001188573d6000803e3d6000fd5b505050506040513d60208110156200119f57600080fd5b50516001600160a01b03163314620011fe576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b60405163623faf6160e01b8152602060048201908152602482018490526001600160a01b0386169163623faf619186918691908190604401848480828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b1580156200127357600080fd5b505af115801562001288573d6000803e3d6000fd5b5050505050505050565b6000818152600f6020526040812060010154600160201b90046001600160a01b0316620012c257506000620006f0565b6000828152600f60209081526040918290206001015482516370a0823160e01b81526001600160a01b0387811660048301529351600160201b909204909316926370a08231926024808301939192829003018186803b1580156200132557600080fd5b505afa1580156200133a573d6000803e3d6000fd5b505050506040513d60208110156200135157600080fd5b50519392505050565b80806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156200139757600080fd5b505af1158015620013ac573d6000803e3d6000fd5b505050506040513d6020811015620013c357600080fd5b50516001600160a01b0316331462001422576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b816001600160a01b03166359fc20bb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200145e57600080fd5b505af115801562001473573d6000803e3d6000fd5b505050505050565b600f602052600090815260409020805460019091015463ffffffff811690600160201b90046001600160a01b031683565b620014b6620018dd565b62000e008162001b7d565b620014cb620018dd565b62000e008162001c87565b6001602052600090815260409020546001600160a01b031681565b600c54600160201b900463ffffffff1681565b600e546001600160a01b031681565b600c54600090819081906200154590620f4240906200153e90879063ffffffff9081169062001d4216565b9062001da0565b9050600062001560866200155a878562001797565b62001de4565b96919550909350505050565b600c5463ffffffff1690565b6000546001600160a01b031681565b60008054906101000a90046001600160a01b03166001600160a01b0316635c975abb6040518163ffffffff1660e01b815260040160206040518083038186803b158015620015d457600080fd5b505afa158015620015e9573d6000803e3d6000fd5b505050506040513d60208110156200160057600080fd5b5051156200163e576040805162461bcd60e51b815260206004820152600660248201526514185d5cd95960d21b604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316632e292fc76040518163ffffffff1660e01b815260040160206040518083038186803b1580156200168b57600080fd5b505afa158015620016a0573d6000803e3d6000fd5b505050506040513d6020811015620016b757600080fd5b505115620016fd576040805162461bcd60e51b815260206004820152600e60248201526d14185c9d1a585b0b5c185d5cd95960921b604482015290519081900360640190fd5b565b60006200170b6200200c565b90506001600160a01b038116156200179357806001600160a01b0316631d1c2fec836040518263ffffffff1660e01b815260040180828152602001915050602060405180830381600087803b1580156200176457600080fd5b505af115801562001779573d6000803e3d6000fd5b505050506040513d60208110156200179057600080fd5b50505b5050565b6000620017db83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525062002079565b9392505050565b6000805460408051637bb20d2f60e11b81527f45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b505afa15801562001864573d6000803e3d6000fd5b505050506040513d60208110156200187b57600080fd5b5051905090565b600082820183811015620017db576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008054906101000a90046001600160a01b03166001600160a01b0316634fc07d756040518163ffffffff1660e01b815260040160206040518083038186803b1580156200192a57600080fd5b505afa1580156200193f573d6000803e3d6000fd5b505050506040513d60208110156200195657600080fd5b50516001600160a01b03163314620016fd5760405162461bcd60e51b8152600401808060200182810382526022815260200180620035776022913960400191505060405180910390fd5b60008111620019e15760405162461bcd60e51b8152600401808060200182810382526024815260200180620035326024913960400191505060405180910390fd5b600d819055604080516020808252601690820152751b5a5b9a5b5d5b50dd5c985d1a5bdb91195c1bdcda5d60521b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c9181900360600190a150565b6000805460408051637bb20d2f60e11b81527f1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d167034600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b6001600160a01b03811662001b04576040805162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9bdb1b195c881b5d5cdd081899481cd95d60521b604482015290519081900360640190fd5b600080546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f4ff638452bbf33c012645d18ae6f05515ff5f2d1dfb0cece8cbf018c60903f709181900360200190a150565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b60008163ffffffff161162001bc45760405162461bcd60e51b8152600401808060200182810382526021815260200180620035996021913960400191505060405180910390fd5b620f424063ffffffff8216111562001c0e5760405162461bcd60e51b8152600401808060200182810382526033815260200180620035ba6033913960400191505060405180910390fd5b600c805467ffffffff000000001916600160201b63ffffffff8416021790556040805160208082526013908201527264656661756c7452657365727665526174696f60681b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b620f424063ffffffff8216111562001cd15760405162461bcd60e51b8152600401808060200182810382526039815260200180620036106039913960400191505060405180910390fd5b600c805463ffffffff191663ffffffff8316179055604080516020808252601590820152746375726174696f6e54617850657263656e7461676560581b8183015290517f96d5a4b4edf1cefd0900c166d64447f8da1d01d1861a6a60894b5b82a2c15c3c916060908290030190a150565b60008262001d5357506000620006f0565b8282028284828162001d6157fe5b0414620017db5760405162461bcd60e51b8152600401808060200182810382526021815260200180620035566021913960400191505060405180910390fd5b6000620017db83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525062002114565b600062001df06200217d565b506000838152600f60209081526040918290208251606081018452815480825260019092015463ffffffff811693820193909352600160201b9092046001600160a01b0316928201929092529062001f5f57600d5483101562001e855760405162461bcd60e51b815260040180806020018281038252602a81526020018062003433602a913960400191505060405180910390fd5b600e54600d54600c5462001f5692670de0b6b3a7640000926001600160a01b03909116916329a00e7c91849163ffffffff600160201b90910481169062001ed1908b9084906200179716565b6040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001f2157600080fd5b505afa15801562001f36573d6000803e3d6000fd5b505050506040513d602081101562001f4d57600080fd5b50519062001882565b915050620006f0565b600e546001600160a01b03166329a00e7c62001f7b8662000f6a565b83600001518460200151876040518563ffffffff1660e01b8152600401808581526020018481526020018363ffffffff16815260200182815260200194505050505060206040518083038186803b15801562001fd657600080fd5b505afa15801562001feb573d6000803e3d6000fd5b505050506040513d60208110156200200257600080fd5b5051949350505050565b6000805460408051637bb20d2f60e11b81527f966f1e8d8d8014e05f6ec4a57138da9be1f7c5a7f802928a18072f7c53180761600482015290516001600160a01b039092169163f7641a5e91602480820192602092909190829003018186803b1580156200184f57600080fd5b600081848411156200210c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620020d0578181015183820152602001620020b6565b50505050905090810190601f168015620020fe5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183620021665760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620020d0578181015183820152602001620020b6565b5060008385816200217357fe5b0495945050505050565b604080516060810182526000808252602082018190529181019190915290565b61128780620021ac8339019056fe60806040523480156200001157600080fd5b506040516200128738038062001287833981810160405260208110156200003757600080fd5b5051604080518082018252601481527f4772617068204375726174696f6e2053686172650000000000000000000000006020828101918252835180850190945260038085526247435360e81b9185019190915282519293926200009b929062000109565b508051620000b190600490602084019062000109565b505060058054601260ff1990911617905550620000da81620000e1602090811b620009aa17901c565b50620001b5565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826200014157600085556200018c565b82601f106200015c57805160ff19168380011785556200018c565b828001600101855582156200018c579182015b828111156200018c5782518255916020019190600101906200016f565b506200019a9291506200019e565b5090565b5b808211156200019a57600081556001016200019f565b6110c280620001c56000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c806370a08231116100a2578063a457c2d711610071578063a457c2d71461031b578063a9059cbb14610347578063dd62ed3e14610373578063e3056a34146103a1578063f2fde38b146103a95761010b565b806370a08231146102b957806379ba5097146102df57806379cc6790146102e757806395d89b41146103135761010b565b806323b872dd116100de57806323b872dd1461020b578063313ce56714610241578063395093511461025f57806340c10f191461028b5761010b565b806306fdde0314610110578063095ea7b31461018d5780630c340a24146101cd57806318160ddd146101f1575b600080fd5b6101186103cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561015257818101518382015260200161013a565b50505050905090810190601f16801561017f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b9600480360360408110156101a357600080fd5b506001600160a01b038135169060200135610465565b604080519115158252519081900360200190f35b6101d5610482565b604080516001600160a01b039092168252519081900360200190f35b6101f9610496565b60408051918252519081900360200190f35b6101b96004803603606081101561022157600080fd5b506001600160a01b0381358116916020810135909116906040013561049c565b610249610523565b6040805160ff9092168252519081900360200190f35b6101b96004803603604081101561027557600080fd5b506001600160a01b03813516906020013561052c565b6102b7600480360360408110156102a157600080fd5b506001600160a01b03813516906020013561057a565b005b6101f9600480360360208110156102cf57600080fd5b50356001600160a01b03166105e5565b6102b7610600565b6102b7600480360360408110156102fd57600080fd5b506001600160a01b038135169060200135610729565b610118610790565b6101b96004803603604081101561033157600080fd5b506001600160a01b0381351690602001356107f1565b6101b96004803603604081101561035d57600080fd5b506001600160a01b038135169060200135610859565b6101f96004803603604081101561038957600080fd5b506001600160a01b038135811691602001351661086d565b6101d5610898565b6102b7600480360360208110156103bf57600080fd5b50356001600160a01b03166108a7565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b820191906000526020600020905b81548152906001019060200180831161043e57829003601f168201915b5050505050905090565b60006104796104726109d2565b84846109d6565b50600192915050565b60055461010090046001600160a01b031681565b60025490565b60006104a9848484610ac2565b610519846104b56109d2565b61051485604051806060016040528060288152602001610fd6602891396001600160a01b038a166000908152600160205260408120906104f36109d2565b6001600160a01b031681526020810191909152604001600020549190610c1d565b6109d6565b5060019392505050565b60055460ff1690565b60006104796105396109d2565b84610514856001600061054a6109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610cb4565b60055461010090046001600160a01b031633146105d7576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610d15565b5050565b6001600160a01b031660009081526020819052604090205490565b6006546001600160a01b03161580159061062457506006546001600160a01b031633145b610675576040805162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f7200604482015290519081900360640190fd5b60058054600680546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b0319909316909355604051938290048116949293919092049091169083907f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f90600090a36006546040516001600160a01b03918216918316907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b60055461010090046001600160a01b03163314610786576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6105e18282610e05565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561045b5780601f106104305761010080835404028352916020019161045b565b60006104796107fe6109d2565b846105148560405180606001604052806025815260200161106860259139600160006108286109d2565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190610c1d565b60006104796108666109d2565b8484610ac2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6006546001600160a01b031681565b60055461010090046001600160a01b03163314610904576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b038116610956576040805162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b604482015290519081900360640190fd5b600680546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b3390565b6001600160a01b038316610a1b5760405162461bcd60e51b81526004018080602001828103825260248152602001806110446024913960400191505060405180910390fd5b6001600160a01b038216610a605760405162461bcd60e51b8152600401808060200182810382526022815260200180610f8e6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b038316610b075760405162461bcd60e51b815260040180806020018281038252602581526020018061101f6025913960400191505060405180910390fd5b6001600160a01b038216610b4c5760405162461bcd60e51b8152600401808060200182810382526023815260200180610f496023913960400191505060405180910390fd5b610b57838383610f01565b610b9481604051806060016040528060268152602001610fb0602691396001600160a01b0386166000908152602081905260409020549190610c1d565b6001600160a01b038085166000908152602081905260408082209390935590841681522054610bc39082610cb4565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b60008184841115610cac5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610c71578181015183820152602001610c59565b50505050905090810190601f168015610c9e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600082820183811015610d0e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216610d70576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b610d7c60008383610f01565b600254610d899082610cb4565b6002556001600160a01b038216600090815260208190526040902054610daf9082610cb4565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001600160a01b038216610e4a5760405162461bcd60e51b8152600401808060200182810382526021815260200180610ffe6021913960400191505060405180910390fd5b610e5682600083610f01565b610e9381604051806060016040528060228152602001610f6c602291396001600160a01b0385166000908152602081905260409020549190610c1d565b6001600160a01b038316600090815260208190526040902055600254610eb99082610f06565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b505050565b6000610d0e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250610c1d56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212204cb1015622950d635ba48cf5ee6af298ab114e15b9265ae471beca741183788564736f6c634300070400334375726174696f6e206465706f7369742069732062656c6f77206d696e696d756d2072657175697265645375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20636f6c6c656374206665657343616e6e6f74206275726e206d6f7265207369676e616c207468616e20796f75206f776e5369676e616c206d7573742062652061626f7665206f7220657175616c20746f207369676e616c2069737375656420696e20746865206375726174696f6e20706f6f6c5375626772617068206465706c6f796d656e74206d757374206265206375726174656420746f20706572666f726d2063616c63756c6174696f6e734d696e696d756d206375726174696f6e206465706f7369742063616e6e6f742062652030536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7743616c6c6572206d75737420626520436f6e74726f6c6c657220676f7665726e6f7244656661756c74207265736572766520726174696f206d757374206265203e203044656661756c74207265736572766520726174696f2063616e6e6f7420626520686967686572207468616e204d41585f50504d43616c6c6572206d75737420626520746865207374616b696e6720636f6e74726163744375726174696f6e207461782070657263656e74616765206d7573742062652062656c6f77206f7220657175616c20746f204d41585f50504d43616c6c6572206d7573742062652074686520696d706c656d656e746174696f6e43616e6e6f74207472616e7366657220746f6b656e7320746f206465706f736974a26469706673582212206264c30885d86e62b7838b4a997d40aae88812e93904b3faf9131cf287eaf3de64736f6c63430007040033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.