Source Code
Overview
ETH Balance
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 23159340 | 137 days ago | 0 ETH | ||||
| 23159340 | 137 days ago | 0 ETH | ||||
| 23158525 | 137 days ago | 0 ETH | ||||
| 23158525 | 137 days ago | 0 ETH | ||||
| 23158525 | 137 days ago | 0 ETH | ||||
| 23158390 | 137 days ago | 0 ETH | ||||
| 12186163 | 434 days ago | 0 ETH | ||||
| 12186104 | 434 days ago | 0 ETH | ||||
| 12185615 | 434 days ago | 0 ETH | ||||
| 12100315 | 436 days ago | 0 ETH | ||||
| 7483431 | 544 days ago | 0 ETH | ||||
| 7483370 | 544 days ago | 0 ETH | ||||
| 7273977 | 549 days ago | 0 ETH | ||||
| 4239558 | 632 days ago | 0 ETH | ||||
| 3602146 | 654 days ago | 0 ETH | ||||
| 3602124 | 654 days ago | 0 ETH | ||||
| 3320203 | 664 days ago | 0 ETH | ||||
| 3320182 | 664 days ago | 0 ETH | ||||
| 2848144 | 684 days ago | 0 ETH | ||||
| 2376321 | 706 days ago | 0 ETH | ||||
| 2376228 | 706 days ago | 0 ETH | ||||
| 1688764 | 740 days ago | 0 ETH | ||||
| 1688748 | 740 days ago | 0 ETH | ||||
| 1688727 | 740 days ago | 0 ETH | ||||
| 1599844 | 746 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ICHIVaultDeployer
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import { ICHIVault } from "../ICHIVault.sol";
import { IAlgebraFactory } from "@cryptoalgebra/v1.9-core/contracts/interfaces/IAlgebraFactory.sol";
library ICHIVaultDeployer {
function createICHIVault(
address pool,
address token0,
bool allowToken0,
address token1,
bool allowToken1,
uint32 twapPeriod,
uint256 vaultIndex
) public returns (address ichiVault) {
ichiVault = address(
new ICHIVault{ salt: keccak256(abi.encodePacked(msg.sender, token0, allowToken0, token1, allowToken1)) }(
pool,
allowToken0,
allowToken1,
msg.sender,
twapPeriod,
vaultIndex
)
);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IAlgebraPoolActions#mint
/// @notice Any contract that calls IAlgebraPoolActions#mint must implement this interface
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraMintCallback {
/// @notice Called to `msg.sender` after minting liquidity to a position from IAlgebraPool#mint.
/// @dev In the implementation you must pay the pool tokens owed for the minted liquidity.
/// The caller of this method must be checked to be a AlgebraPool deployed by the canonical AlgebraFactory.
/// @param amount0Owed The amount of token0 due to the pool for the minted liquidity
/// @param amount1Owed The amount of token1 due to the pool for the minted liquidity
/// @param data Any data passed through by the caller via the IAlgebraPoolActions#mint call
function algebraMintCallback(
uint256 amount0Owed,
uint256 amount1Owed,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Callback for IAlgebraPoolActions#swap
/// @notice Any contract that calls IAlgebraPoolActions#swap must implement this interface
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraSwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IAlgebraPool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a AlgebraPool deployed by the canonical AlgebraFactory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IAlgebraPoolActions#swap call
function algebraSwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @title The interface for the Algebra Factory
* @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
* https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
*/
interface IAlgebraFactory {
/**
* @notice Emitted when the owner of the factory is changed
* @param newOwner The owner after the owner was changed
*/
event Owner(address indexed newOwner);
/**
* @notice Emitted when the vault address is changed
* @param newVaultAddress The vault address after the address was changed
*/
event VaultAddress(address indexed newVaultAddress);
/**
* @notice Emitted when a pool is created
* @param token0 The first token of the pool by address sort order
* @param token1 The second token of the pool by address sort order
* @param pool The address of the created pool
*/
event Pool(address indexed token0, address indexed token1, address pool);
/**
* @notice Emitted when the farming address is changed
* @param newFarmingAddress The farming address after the address was changed
*/
event FarmingAddress(address indexed newFarmingAddress);
/**
* @notice Emitted when the default community fee is changed
* @param newDefaultCommunityFee The new default community fee value
*/
event DefaultCommunityFee(uint8 newDefaultCommunityFee);
event FeeConfiguration(
uint16 alpha1,
uint16 alpha2,
uint32 beta1,
uint32 beta2,
uint16 gamma1,
uint16 gamma2,
uint32 volumeBeta,
uint16 volumeGamma,
uint16 baseFee
);
/**
* @notice Returns the current owner of the factory
* @dev Can be changed by the current owner via setOwner
* @return The address of the factory owner
*/
function owner() external view returns (address);
/**
* @notice Returns the current poolDeployerAddress
* @return The address of the poolDeployer
*/
function poolDeployer() external view returns (address);
/**
* @dev Is retrieved from the pools to restrict calling
* certain functions not by a tokenomics contract
* @return The tokenomics contract address
*/
function farmingAddress() external view returns (address);
/**
* @notice Returns the default community fee
* @return Fee which will be set at the creation of the pool
*/
function defaultCommunityFee() external view returns (uint8);
function vaultAddress() external view returns (address);
/**
* @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist
* @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order
* @param tokenA The contract address of either token0 or token1
* @param tokenB The contract address of the other token
* @return pool The pool address
*/
function poolByPair(address tokenA, address tokenB) external view returns (address pool);
/**
* @notice Creates a pool for the given two tokens and fee
* @param tokenA One of the two tokens in the desired pool
* @param tokenB The other of the two tokens in the desired pool
* @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved
* from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments
* are invalid.
* @return pool The address of the newly created pool
*/
function createPool(address tokenA, address tokenB) external returns (address pool);
/**
* @notice Updates the owner of the factory
* @dev Must be called by the current owner
* @param _owner The new owner of the factory
*/
function setOwner(address _owner) external;
/**
* @dev updates tokenomics address on the factory
* @param _farmingAddress The new tokenomics contract address
*/
function setFarmingAddress(address _farmingAddress) external;
/**
* @dev updates default community fee for new pools
* @param newDefaultCommunityFee The new community fee, _must_ be <= MAX_COMMUNITY_FEE
*/
function setDefaultCommunityFee(uint8 newDefaultCommunityFee) external;
/**
* @dev updates vault address on the factory
* @param _vaultAddress The new vault contract address
*/
function setVaultAddress(address _vaultAddress) external;
/**
* @notice Changes initial fee configuration for new pools
* @dev changes coefficients for sigmoids: α / (1 + e^( (β-x) / γ))
* alpha1 + alpha2 + baseFee (max possible fee) must be <= type(uint16).max
* gammas must be > 0
* @param alpha1 max value of the first sigmoid
* @param alpha2 max value of the second sigmoid
* @param beta1 shift along the x-axis for the first sigmoid
* @param beta2 shift along the x-axis for the second sigmoid
* @param gamma1 horizontal stretch factor for the first sigmoid
* @param gamma2 horizontal stretch factor for the second sigmoid
* @param volumeBeta shift along the x-axis for the outer volume-sigmoid
* @param volumeGamma horizontal stretch factor the outer volume-sigmoid
* @param baseFee minimum possible fee
*/
function setBaseFeeConfiguration(
uint16 alpha1,
uint16 alpha2,
uint32 beta1,
uint32 beta2,
uint16 gamma1,
uint16 gamma2,
uint32 volumeBeta,
uint16 volumeGamma,
uint16 baseFee
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import './pool/IAlgebraPoolImmutables.sol';
import './pool/IAlgebraPoolState.sol';
import './pool/IAlgebraPoolDerivedState.sol';
import './pool/IAlgebraPoolActions.sol';
import './pool/IAlgebraPoolPermissionedActions.sol';
import './pool/IAlgebraPoolEvents.sol';
/**
* @title The interface for a Algebra Pool
* @dev The pool interface is broken up into many smaller pieces.
* Credit to Uniswap Labs under GPL-2.0-or-later license:
* https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
*/
interface IAlgebraPool is
IAlgebraPoolImmutables,
IAlgebraPoolState,
IAlgebraPoolDerivedState,
IAlgebraPoolActions,
IAlgebraPoolPermissionedActions,
IAlgebraPoolEvents
{
// used only for combining interfaces
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
pragma abicoder v2;
import '../libraries/AdaptiveFee.sol';
interface IDataStorageOperator {
event FeeConfiguration(AdaptiveFee.Configuration feeConfig);
/**
* @notice Returns data belonging to a certain timepoint
* @param index The index of timepoint in the array
* @dev There is more convenient function to fetch a timepoint: getTimepoints(). Which requires not an index but seconds
* @return initialized Whether the timepoint has been initialized and the values are safe to use,
* blockTimestamp The timestamp of the observation,
* tickCumulative The tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp,
* secondsPerLiquidityCumulative The seconds per in range liquidity for the life of the pool as of the timepoint timestamp,
* volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp,
* averageTick Time-weighted average tick,
* volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp
*/
function timepoints(
uint256 index
)
external
view
returns (
bool initialized,
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulative,
uint88 volatilityCumulative,
int24 averageTick,
uint144 volumePerLiquidityCumulative
);
/// @notice Initialize the dataStorage array by writing the first slot. Called once for the lifecycle of the timepoints array
/// @param time The time of the dataStorage initialization, via block.timestamp truncated to uint32
/// @param tick Initial tick
function initialize(uint32 time, int24 tick) external;
/// @dev Reverts if an timepoint at or before the desired timepoint timestamp does not exist.
/// 0 may be passed as `secondsAgo' to return the current cumulative values.
/// If called with a timestamp falling between two timepoints, returns the counterfactual accumulator values
/// at exactly the timestamp between the two timepoints.
/// @param time The current block timestamp
/// @param secondsAgo The amount of time to look back, in seconds, at which point to return an timepoint
/// @param tick The current tick
/// @param index The index of the timepoint that was most recently written to the timepoints array
/// @param liquidity The current in-range pool liquidity
/// @return tickCumulative The cumulative tick since the pool was first initialized, as of `secondsAgo`
/// @return secondsPerLiquidityCumulative The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of `secondsAgo`
/// @return volatilityCumulative The cumulative volatility value since the pool was first initialized, as of `secondsAgo`
/// @return volumePerAvgLiquidity The cumulative volume per liquidity value since the pool was first initialized, as of `secondsAgo`
function getSingleTimepoint(
uint32 time,
uint32 secondsAgo,
int24 tick,
uint16 index,
uint128 liquidity
) external view returns (int56 tickCumulative, uint160 secondsPerLiquidityCumulative, uint112 volatilityCumulative, uint256 volumePerAvgLiquidity);
/// @notice Returns the accumulator values as of each time seconds ago from the given time in the array of `secondsAgos`
/// @dev Reverts if `secondsAgos` > oldest timepoint
/// @param time The current block.timestamp
/// @param secondsAgos Each amount of time to look back, in seconds, at which point to return an timepoint
/// @param tick The current tick
/// @param index The index of the timepoint that was most recently written to the timepoints array
/// @param liquidity The current in-range pool liquidity
/// @return tickCumulatives The cumulative tick since the pool was first initialized, as of each `secondsAgo`
/// @return secondsPerLiquidityCumulatives The cumulative seconds / max(1, liquidity) since the pool was first initialized, as of each `secondsAgo`
/// @return volatilityCumulatives The cumulative volatility values since the pool was first initialized, as of each `secondsAgo`
/// @return volumePerAvgLiquiditys The cumulative volume per liquidity values since the pool was first initialized, as of each `secondsAgo`
function getTimepoints(
uint32 time,
uint32[] memory secondsAgos,
int24 tick,
uint16 index,
uint128 liquidity
)
external
view
returns (
int56[] memory tickCumulatives,
uint160[] memory secondsPerLiquidityCumulatives,
uint112[] memory volatilityCumulatives,
uint256[] memory volumePerAvgLiquiditys
);
/// @notice Returns average volatility in the range from time-WINDOW to time
/// @param time The current block.timestamp
/// @param tick The current tick
/// @param index The index of the timepoint that was most recently written to the timepoints array
/// @param liquidity The current in-range pool liquidity
/// @return TWVolatilityAverage The average volatility in the recent range
/// @return TWVolumePerLiqAverage The average volume per liquidity in the recent range
function getAverages(
uint32 time,
int24 tick,
uint16 index,
uint128 liquidity
) external view returns (uint112 TWVolatilityAverage, uint256 TWVolumePerLiqAverage);
/// @notice Writes an dataStorage timepoint to the array
/// @dev Writable at most once per block. Index represents the most recently written element. index must be tracked externally.
/// @param index The index of the timepoint that was most recently written to the timepoints array
/// @param blockTimestamp The timestamp of the new timepoint
/// @param tick The active tick at the time of the new timepoint
/// @param liquidity The total in-range liquidity at the time of the new timepoint
/// @param volumePerLiquidity The gmean(volumes)/liquidity at the time of the new timepoint
/// @return indexUpdated The new index of the most recently written element in the dataStorage array
function write(
uint16 index,
uint32 blockTimestamp,
int24 tick,
uint128 liquidity,
uint128 volumePerLiquidity
) external returns (uint16 indexUpdated);
/// @notice Changes fee configuration for the pool
function changeFeeConfiguration(AdaptiveFee.Configuration calldata feeConfig) external;
/// @notice Calculates gmean(volume/liquidity) for block
/// @param liquidity The current in-range pool liquidity
/// @param amount0 Total amount of swapped token0
/// @param amount1 Total amount of swapped token1
/// @return volumePerLiquidity gmean(volume/liquidity) capped by 100000 << 64
function calculateVolumePerLiquidity(uint128 liquidity, int256 amount0, int256 amount1) external pure returns (uint128 volumePerLiquidity);
/// @return windowLength Length of window used to calculate averages
function window() external view returns (uint32 windowLength);
/// @notice Calculates fee based on combination of sigmoids
/// @param time The current block.timestamp
/// @param tick The current tick
/// @param index The index of the timepoint that was most recently written to the timepoints array
/// @param liquidity The current in-range pool liquidity
/// @return fee The fee in hundredths of a bip, i.e. 1e-6
function getFee(uint32 time, int24 tick, uint16 index, uint128 liquidity) external view returns (uint16 fee);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Permissionless pool actions
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolActions {
/**
* @notice Sets the initial price for the pool
* @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value
* @param price the initial sqrt price of the pool as a Q64.96
*/
function initialize(uint160 price) external;
/**
* @notice Adds liquidity for the given recipient/bottomTick/topTick position
* @dev The caller of this method receives a callback in the form of IAlgebraMintCallback# AlgebraMintCallback
* in which they must pay any token0 or token1 owed for the liquidity. The amount of token0/token1 due depends
* on bottomTick, topTick, the amount of liquidity, and the current price.
* @param sender The address which will receive potential surplus of paid tokens
* @param recipient The address for which the liquidity will be created
* @param bottomTick The lower tick of the position in which to add liquidity
* @param topTick The upper tick of the position in which to add liquidity
* @param amount The desired amount of liquidity to mint
* @param data Any data that should be passed through to the callback
* @return amount0 The amount of token0 that was paid to mint the given amount of liquidity. Matches the value in the callback
* @return amount1 The amount of token1 that was paid to mint the given amount of liquidity. Matches the value in the callback
* @return liquidityActual The actual minted amount of liquidity
*/
function mint(
address sender,
address recipient,
int24 bottomTick,
int24 topTick,
uint128 amount,
bytes calldata data
)
external
returns (
uint256 amount0,
uint256 amount1,
uint128 liquidityActual
);
/**
* @notice Collects tokens owed to a position
* @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity.
* Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or
* amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the
* actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity.
* @param recipient The address which should receive the fees collected
* @param bottomTick The lower tick of the position for which to collect fees
* @param topTick The upper tick of the position for which to collect fees
* @param amount0Requested How much token0 should be withdrawn from the fees owed
* @param amount1Requested How much token1 should be withdrawn from the fees owed
* @return amount0 The amount of fees collected in token0
* @return amount1 The amount of fees collected in token1
*/
function collect(
address recipient,
int24 bottomTick,
int24 topTick,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
/**
* @notice Burn liquidity from the sender and account tokens owed for the liquidity to the position
* @dev Can be used to trigger a recalculation of fees owed to a position by calling with an amount of 0
* @dev Fees must be collected separately via a call to #collect
* @param bottomTick The lower tick of the position for which to burn liquidity
* @param topTick The upper tick of the position for which to burn liquidity
* @param amount How much liquidity to burn
* @return amount0 The amount of token0 sent to the recipient
* @return amount1 The amount of token1 sent to the recipient
*/
function burn(
int24 bottomTick,
int24 topTick,
uint128 amount
) external returns (uint256 amount0, uint256 amount1);
/**
* @notice Swap token0 for token1, or token1 for token0
* @dev The caller of this method receives a callback in the form of IAlgebraSwapCallback# AlgebraSwapCallback
* @param recipient The address to receive the output of the swap
* @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
* @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
* value after the swap. If one for zero, the price cannot be greater than this value after the swap
* @param data Any data to be passed through to the callback. If using the Router it should contain
* SwapRouter#SwapCallbackData
* @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
* @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
*/
function swap(
address recipient,
bool zeroToOne,
int256 amountSpecified,
uint160 limitSqrtPrice,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
/**
* @notice Swap token0 for token1, or token1 for token0 (tokens that have fee on transfer)
* @dev The caller of this method receives a callback in the form of I AlgebraSwapCallback# AlgebraSwapCallback
* @param sender The address called this function (Comes from the Router)
* @param recipient The address to receive the output of the swap
* @param zeroToOne The direction of the swap, true for token0 to token1, false for token1 to token0
* @param amountSpecified The amount of the swap, which implicitly configures the swap as exact input (positive), or exact output (negative)
* @param limitSqrtPrice The Q64.96 sqrt price limit. If zero for one, the price cannot be less than this
* value after the swap. If one for zero, the price cannot be greater than this value after the swap
* @param data Any data to be passed through to the callback. If using the Router it should contain
* SwapRouter#SwapCallbackData
* @return amount0 The delta of the balance of token0 of the pool, exact when negative, minimum when positive
* @return amount1 The delta of the balance of token1 of the pool, exact when negative, minimum when positive
*/
function swapSupportingFeeOnInputTokens(
address sender,
address recipient,
bool zeroToOne,
int256 amountSpecified,
uint160 limitSqrtPrice,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
/**
* @notice Receive token0 and/or token1 and pay it back, plus a fee, in the callback
* @dev The caller of this method receives a callback in the form of IAlgebraFlashCallback# AlgebraFlashCallback
* @dev All excess tokens paid in the callback are distributed to liquidity providers as an additional fee. So this method can be used
* to donate underlying tokens to currently in-range liquidity providers by calling with 0 amount{0,1} and sending
* the donation amount(s) from the callback
* @param recipient The address which will receive the token0 and token1 amounts
* @param amount0 The amount of token0 to send
* @param amount1 The amount of token1 to send
* @param data Any data to be passed through to the callback
*/
function flash(
address recipient,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @title Pool state that is not stored
* @notice Contains view functions to provide information about the pool that is computed rather than stored on the
* blockchain. The functions here may have variable gas costs.
* @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
* https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
*/
interface IAlgebraPoolDerivedState {
/**
* @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
* @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
* the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
* you must call it with secondsAgos = [3600, 0].
* @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
* log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
* @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
* @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
* @return secondsPerLiquidityCumulatives Cumulative seconds per liquidity-in-range value as of each `secondsAgos`
* from the current block timestamp
* @return volatilityCumulatives Cumulative standard deviation as of each `secondsAgos`
* @return volumePerAvgLiquiditys Cumulative swap volume per liquidity as of each `secondsAgos`
*/
function getTimepoints(uint32[] calldata secondsAgos)
external
view
returns (
int56[] memory tickCumulatives,
uint160[] memory secondsPerLiquidityCumulatives,
uint112[] memory volatilityCumulatives,
uint256[] memory volumePerAvgLiquiditys
);
/**
* @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range
* @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed.
* I.e., snapshots cannot be compared if a position is not held for the entire period between when the first
* snapshot is taken and the second snapshot is taken.
* @param bottomTick The lower tick of the range
* @param topTick The upper tick of the range
* @return innerTickCumulative The snapshot of the tick accumulator for the range
* @return innerSecondsSpentPerLiquidity The snapshot of seconds per liquidity for the range
* @return innerSecondsSpent The snapshot of the number of seconds during which the price was in this range
*/
function getInnerCumulatives(int24 bottomTick, int24 topTick)
external
view
returns (
int56 innerTickCumulative,
uint160 innerSecondsSpentPerLiquidity,
uint32 innerSecondsSpent
);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Events emitted by a pool
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolEvents {
/**
* @notice Emitted exactly once by a pool when #initialize is first called on the pool
* @dev Mint/Burn/Swap cannot be emitted by the pool before Initialize
* @param price The initial sqrt price of the pool, as a Q64.96
* @param tick The initial tick of the pool, i.e. log base 1.0001 of the starting price of the pool
*/
event Initialize(uint160 price, int24 tick);
/**
* @notice Emitted when liquidity is minted for a given position
* @param sender The address that minted the liquidity
* @param owner The owner of the position and recipient of any minted liquidity
* @param bottomTick The lower tick of the position
* @param topTick The upper tick of the position
* @param liquidityAmount The amount of liquidity minted to the position range
* @param amount0 How much token0 was required for the minted liquidity
* @param amount1 How much token1 was required for the minted liquidity
*/
event Mint(
address sender,
address indexed owner,
int24 indexed bottomTick,
int24 indexed topTick,
uint128 liquidityAmount,
uint256 amount0,
uint256 amount1
);
/**
* @notice Emitted when fees are collected by the owner of a position
* @dev Collect events may be emitted with zero amount0 and amount1 when the caller chooses not to collect fees
* @param owner The owner of the position for which fees are collected
* @param recipient The address that received fees
* @param bottomTick The lower tick of the position
* @param topTick The upper tick of the position
* @param amount0 The amount of token0 fees collected
* @param amount1 The amount of token1 fees collected
*/
event Collect(address indexed owner, address recipient, int24 indexed bottomTick, int24 indexed topTick, uint128 amount0, uint128 amount1);
/**
* @notice Emitted when a position's liquidity is removed
* @dev Does not withdraw any fees earned by the liquidity position, which must be withdrawn via #collect
* @param owner The owner of the position for which liquidity is removed
* @param bottomTick The lower tick of the position
* @param topTick The upper tick of the position
* @param liquidityAmount The amount of liquidity to remove
* @param amount0 The amount of token0 withdrawn
* @param amount1 The amount of token1 withdrawn
*/
event Burn(address indexed owner, int24 indexed bottomTick, int24 indexed topTick, uint128 liquidityAmount, uint256 amount0, uint256 amount1);
/**
* @notice Emitted by the pool for any swaps between token0 and token1
* @param sender The address that initiated the swap call, and that received the callback
* @param recipient The address that received the output of the swap
* @param amount0 The delta of the token0 balance of the pool
* @param amount1 The delta of the token1 balance of the pool
* @param price The sqrt(price) of the pool after the swap, as a Q64.96
* @param liquidity The liquidity of the pool after the swap
* @param tick The log base 1.0001 of price of the pool after the swap
*/
event Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 price, uint128 liquidity, int24 tick);
/**
* @notice Emitted by the pool for any flashes of token0/token1
* @param sender The address that initiated the swap call, and that received the callback
* @param recipient The address that received the tokens from flash
* @param amount0 The amount of token0 that was flashed
* @param amount1 The amount of token1 that was flashed
* @param paid0 The amount of token0 paid for the flash, which can exceed the amount0 plus the fee
* @param paid1 The amount of token1 paid for the flash, which can exceed the amount1 plus the fee
*/
event Flash(address indexed sender, address indexed recipient, uint256 amount0, uint256 amount1, uint256 paid0, uint256 paid1);
/**
* @notice Emitted when the community fee is changed by the pool
* @param communityFee0New The updated value of the token0 community fee percent
* @param communityFee1New The updated value of the token1 community fee percent
*/
event CommunityFee(uint8 communityFee0New, uint8 communityFee1New);
/**
* @notice Emitted when the tick spacing changes
* @param newTickSpacing The updated value of the new tick spacing
*/
event TickSpacing(int24 newTickSpacing);
/**
* @notice Emitted when new activeIncentive is set
* @param virtualPoolAddress The address of a virtual pool associated with the current active incentive
*/
event Incentive(address indexed virtualPoolAddress);
/**
* @notice Emitted when the fee changes
* @param fee The value of the token fee
*/
event Fee(uint16 fee);
/**
* @notice Emitted when the LiquidityCooldown changes
* @param liquidityCooldown The value of locktime for added liquidity
*/
event LiquidityCooldown(uint32 liquidityCooldown);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import '../IDataStorageOperator.sol';
/// @title Pool state that never changes
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolImmutables {
/**
* @notice The contract that stores all the timepoints and can perform actions with them
* @return The operator address
*/
function dataStorageOperator() external view returns (address);
/**
* @notice The contract that deployed the pool, which must adhere to the IAlgebraFactory interface
* @return The contract address
*/
function factory() external view returns (address);
/**
* @notice The first of the two tokens of the pool, sorted by address
* @return The token contract address
*/
function token0() external view returns (address);
/**
* @notice The second of the two tokens of the pool, sorted by address
* @return The token contract address
*/
function token1() external view returns (address);
/**
* @notice The maximum amount of position liquidity that can use any tick in the range
* @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and
* also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool
* @return The max amount of liquidity per tick
*/
function maxLiquidityPerTick() external view returns (uint128);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/**
* @title Permissioned pool actions
* @notice Contains pool methods that may only be called by the factory owner or tokenomics
* @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
* https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
*/
interface IAlgebraPoolPermissionedActions {
/**
* @notice Set the community's % share of the fees. Cannot exceed 25% (250)
* @param communityFee0 new community fee percent for token0 of the pool in thousandths (1e-3)
* @param communityFee1 new community fee percent for token1 of the pool in thousandths (1e-3)
*/
function setCommunityFee(uint8 communityFee0, uint8 communityFee1) external;
/// @notice Set the new tick spacing values. Only factory owner
/// @param newTickSpacing The new tick spacing value
function setTickSpacing(int24 newTickSpacing) external;
/**
* @notice Sets an active incentive
* @param virtualPoolAddress The address of a virtual pool associated with the incentive
*/
function setIncentive(address virtualPoolAddress) external;
/**
* @notice Sets new lock time for added liquidity
* @param newLiquidityCooldown The time in seconds
*/
function setLiquidityCooldown(uint32 newLiquidityCooldown) external;
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Pool state that can change
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces
interface IAlgebraPoolState {
/**
* @notice The globalState structure in the pool stores many values but requires only one slot
* and is exposed as a single method to save gas when accessed externally.
* @return price The current price of the pool as a sqrt(token1/token0) Q64.96 value;
* Returns tick The current tick of the pool, i.e. according to the last tick transition that was run;
* Returns This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(price) if the price is on a tick
* boundary;
* Returns fee The last pool fee value in hundredths of a bip, i.e. 1e-6;
* Returns timepointIndex The index of the last written timepoint;
* Returns communityFeeToken0 The community fee percentage of the swap fee in thousandths (1e-3) for token0;
* Returns communityFeeToken1 The community fee percentage of the swap fee in thousandths (1e-3) for token1;
* Returns unlocked Whether the pool is currently locked to reentrancy;
*/
function globalState()
external
view
returns (
uint160 price,
int24 tick,
uint16 fee,
uint16 timepointIndex,
uint8 communityFeeToken0,
uint8 communityFeeToken1,
bool unlocked
);
/**
* @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool
* @dev This value can overflow the uint256
*/
function totalFeeGrowth0Token() external view returns (uint256);
/**
* @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool
* @dev This value can overflow the uint256
*/
function totalFeeGrowth1Token() external view returns (uint256);
/**
* @notice The currently in range liquidity available to the pool
* @dev This value has no relationship to the total liquidity across all ticks.
* Returned value cannot exceed type(uint128).max
*/
function liquidity() external view returns (uint128);
/**
* @notice Look up information about a specific tick in the pool
* @dev This is a public structure, so the `return` natspec tags are omitted.
* @param tick The tick to look up
* @return liquidityTotal the total amount of position liquidity that uses the pool either as tick lower or
* tick upper;
* Returns liquidityDelta how much liquidity changes when the pool price crosses the tick;
* Returns outerFeeGrowth0Token the fee growth on the other side of the tick from the current tick in token0;
* Returns outerFeeGrowth1Token the fee growth on the other side of the tick from the current tick in token1;
* Returns outerTickCumulative the cumulative tick value on the other side of the tick from the current tick;
* Returns outerSecondsPerLiquidity the seconds spent per liquidity on the other side of the tick from the current tick;
* Returns outerSecondsSpent the seconds spent on the other side of the tick from the current tick;
* Returns initialized Set to true if the tick is initialized, i.e. liquidityTotal is greater than 0
* otherwise equal to false. Outside values can only be used if the tick is initialized.
* In addition, these values are only relative and must be used only in comparison to previous snapshots for
* a specific position.
*/
function ticks(int24 tick)
external
view
returns (
uint128 liquidityTotal,
int128 liquidityDelta,
uint256 outerFeeGrowth0Token,
uint256 outerFeeGrowth1Token,
int56 outerTickCumulative,
uint160 outerSecondsPerLiquidity,
uint32 outerSecondsSpent,
bool initialized
);
/** @notice Returns 256 packed tick initialized boolean values. See TickTable for more information */
function tickTable(int16 wordPosition) external view returns (uint256);
/**
* @notice Returns the information about a position by the position's key
* @dev This is a public mapping of structures, so the `return` natspec tags are omitted.
* @param key The position's key is a hash of a preimage composed by the owner, bottomTick and topTick
* @return liquidityAmount The amount of liquidity in the position;
* Returns lastLiquidityAddTimestamp Timestamp of last adding of liquidity;
* Returns innerFeeGrowth0Token Fee growth of token0 inside the tick range as of the last mint/burn/poke;
* Returns innerFeeGrowth1Token Fee growth of token1 inside the tick range as of the last mint/burn/poke;
* Returns fees0 The computed amount of token0 owed to the position as of the last mint/burn/poke;
* Returns fees1 The computed amount of token1 owed to the position as of the last mint/burn/poke
*/
function positions(bytes32 key)
external
view
returns (
uint128 liquidityAmount,
uint32 lastLiquidityAddTimestamp,
uint256 innerFeeGrowth0Token,
uint256 innerFeeGrowth1Token,
uint128 fees0,
uint128 fees1
);
/**
* @notice Returns data about a specific timepoint index
* @param index The element of the timepoints array to fetch
* @dev You most likely want to use #getTimepoints() instead of this method to get an timepoint as of some amount of time
* ago, rather than at a specific index in the array.
* This is a public mapping of structures, so the `return` natspec tags are omitted.
* @return initialized whether the timepoint has been initialized and the values are safe to use;
* Returns blockTimestamp The timestamp of the timepoint;
* Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the timepoint timestamp;
* Returns secondsPerLiquidityCumulative the seconds per in range liquidity for the life of the pool as of the timepoint timestamp;
* Returns volatilityCumulative Cumulative standard deviation for the life of the pool as of the timepoint timestamp;
* Returns averageTick Time-weighted average tick;
* Returns volumePerLiquidityCumulative Cumulative swap volume per liquidity for the life of the pool as of the timepoint timestamp;
*/
function timepoints(uint256 index)
external
view
returns (
bool initialized,
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulative,
uint88 volatilityCumulative,
int24 averageTick,
uint144 volumePerLiquidityCumulative
);
/**
* @notice Returns the information about active incentive
* @dev if there is no active incentive at the moment, virtualPool,endTimestamp,startTimestamp would be equal to 0
* @return virtualPool The address of a virtual pool associated with the current active incentive
*/
function activeIncentive() external view returns (address virtualPool);
/**
* @notice Returns the lock time for added liquidity
*/
function liquidityCooldown() external view returns (uint32 cooldownInSeconds);
/**
* @notice The pool tick spacing
* @dev Ticks can only be used at multiples of this value
* e.g.: a tickSpacing of 60 means ticks can be initialized every 60th tick, i.e., ..., -120, -60, 0, 60, 120, ...
* This value is an int24 to avoid casting even though it is always positive.
* @return The tick spacing
*/
function tickSpacing() external view returns (int24);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.7.6;
import './Constants.sol';
/// @title AdaptiveFee
/// @notice Calculates fee based on combination of sigmoids
library AdaptiveFee {
// alpha1 + alpha2 + baseFee must be <= type(uint16).max
struct Configuration {
uint16 alpha1; // max value of the first sigmoid
uint16 alpha2; // max value of the second sigmoid
uint32 beta1; // shift along the x-axis for the first sigmoid
uint32 beta2; // shift along the x-axis for the second sigmoid
uint16 gamma1; // horizontal stretch factor for the first sigmoid
uint16 gamma2; // horizontal stretch factor for the second sigmoid
uint32 volumeBeta; // shift along the x-axis for the outer volume-sigmoid
uint16 volumeGamma; // horizontal stretch factor the outer volume-sigmoid
uint16 baseFee; // minimum possible fee
}
/// @notice Calculates fee based on formula:
/// baseFee + sigmoidVolume(sigmoid1(volatility, volumePerLiquidity) + sigmoid2(volatility, volumePerLiquidity))
/// maximum value capped by baseFee + alpha1 + alpha2
function getFee(
uint88 volatility,
uint256 volumePerLiquidity,
Configuration memory config
) internal pure returns (uint16 fee) {
uint256 sumOfSigmoids = sigmoid(volatility, config.gamma1, config.alpha1, config.beta1) +
sigmoid(volatility, config.gamma2, config.alpha2, config.beta2);
if (sumOfSigmoids > type(uint16).max) {
// should be impossible, just in case
sumOfSigmoids = type(uint16).max;
}
return uint16(config.baseFee + sigmoid(volumePerLiquidity, config.volumeGamma, uint16(sumOfSigmoids), config.volumeBeta)); // safe since alpha1 + alpha2 + baseFee _must_ be <= type(uint16).max
}
/// @notice calculates α / (1 + e^( (β-x) / γ))
/// that is a sigmoid with a maximum value of α, x-shifted by β, and stretched by γ
/// @dev returns uint256 for fuzzy testing. Guaranteed that the result is not greater than alpha
function sigmoid(
uint256 x,
uint16 g,
uint16 alpha,
uint256 beta
) internal pure returns (uint256 res) {
if (x > beta) {
x = x - beta;
if (x >= 6 * uint256(g)) return alpha; // so x < 19 bits
uint256 g8 = uint256(g)**8; // < 128 bits (8*16)
uint256 ex = exp(x, g, g8); // < 155 bits
res = (alpha * ex) / (g8 + ex); // in worst case: (16 + 155 bits) / 155 bits
// so res <= alpha
} else {
x = beta - x;
if (x >= 6 * uint256(g)) return 0; // so x < 19 bits
uint256 g8 = uint256(g)**8; // < 128 bits (8*16)
uint256 ex = g8 + exp(x, g, g8); // < 156 bits
res = (alpha * g8) / ex; // in worst case: (16 + 128 bits) / 156 bits
// g8 <= ex, so res <= alpha
}
}
/// @notice calculates e^(x/g) * g^8 in a series, since (around zero):
/// e^x = 1 + x + x^2/2 + ... + x^n/n! + ...
/// e^(x/g) = 1 + x/g + x^2/(2*g^2) + ... + x^(n)/(g^n * n!) + ...
function exp(
uint256 x,
uint16 g,
uint256 gHighestDegree
) internal pure returns (uint256 res) {
// calculating:
// g**8 + x * g**7 + (x**2 * g**6) / 2 + (x**3 * g**5) / 6 + (x**4 * g**4) / 24 + (x**5 * g**3) / 120 + (x**6 * g^2) / 720 + x**7 * g / 5040 + x**8 / 40320
// x**8 < 152 bits (19*8) and g**8 < 128 bits (8*16)
// so each summand < 152 bits and res < 155 bits
uint256 xLowestDegree = x;
res = gHighestDegree; // g**8
gHighestDegree /= g; // g**7
res += xLowestDegree * gHighestDegree;
gHighestDegree /= g; // g**6
xLowestDegree *= x; // x**2
res += (xLowestDegree * gHighestDegree) / 2;
gHighestDegree /= g; // g**5
xLowestDegree *= x; // x**3
res += (xLowestDegree * gHighestDegree) / 6;
gHighestDegree /= g; // g**4
xLowestDegree *= x; // x**4
res += (xLowestDegree * gHighestDegree) / 24;
gHighestDegree /= g; // g**3
xLowestDegree *= x; // x**5
res += (xLowestDegree * gHighestDegree) / 120;
gHighestDegree /= g; // g**2
xLowestDegree *= x; // x**6
res += (xLowestDegree * gHighestDegree) / 720;
xLowestDegree *= x; // x**7
res += (xLowestDegree * g) / 5040 + (xLowestDegree * x) / (40320);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
library Constants {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000;
uint256 internal constant Q128 = 0x100000000000000000000000000000000;
// fee value in hundredths of a bip, i.e. 1e-6
uint16 internal constant BASE_FEE = 100;
int24 internal constant MAX_TICK_SPACING = 500;
// max(uint128) / (MAX_TICK - MIN_TICK)
uint128 internal constant MAX_LIQUIDITY_PER_TICK = 191757638537527648490752896198553;
uint32 internal constant MAX_LIQUIDITY_COOLDOWN = 1 days;
uint8 internal constant MAX_COMMUNITY_FEE = 250;
uint256 internal constant COMMUNITY_FEE_DENOMINATOR = 1000;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2**256 + prod0
uint256 prod0 = a * b; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
assembly {
result := div(prod0, denominator)
}
return result;
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
// Subtract 256 bit remainder from 512 bit number
assembly {
let remainder := mulmod(a, b, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
uint256 twos = -denominator & denominator;
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
// Invert denominator mod 2**256
// Now that denominator is an odd number, it has an inverse
// modulo 2**256 such that denominator * inv = 1 mod 2**256.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use Newton-Raphson iteration to improve the precision.
// Thanks to Hensel's lifting lemma, this also works in modular
// arithmetic, doubling the correct bits in each step.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // inverse mod 2**256
// Because the division is now exact we can divide by multiplying
// with the modular inverse of denominator. This will give us the
// correct result modulo 2**256. Since the preconditions guarantee
// that the outcome is less than 2**256, this is the final result.
// We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inv;
return result;
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
if (a == 0 || ((result = a * b) / a == b)) {
require(denominator > 0);
assembly {
result := add(div(result, denominator), gt(mod(result, denominator), 0))
}
} else {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}
/// @notice Returns ceil(x / y)
/// @dev division by 0 has unspecified behavior, and must be checked externally
/// @param x The dividend
/// @param y The divisor
/// @return z The quotient, ceil(x / y)
function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := add(div(x, y), gt(mod(x, y), 0))
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.0;
/// @title Optimized overflow and underflow safe math operations
/// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas cost
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries
library LowGasSafeMath {
/// @notice Returns x + y, reverts if sum overflows uint256
/// @param x The augend
/// @param y The addend
/// @return z The sum of x and y
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x);
}
/// @notice Returns x - y, reverts if underflows
/// @param x The minuend
/// @param y The subtrahend
/// @return z The difference of x and y
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x - y) <= x);
}
/// @notice Returns x * y, reverts if overflows
/// @param x The multiplicand
/// @param y The multiplier
/// @return z The product of x and y
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(x == 0 || (z = x * y) / x == y);
}
/// @notice Returns x + y, reverts if overflows or underflows
/// @param x The augend
/// @param y The addend
/// @return z The sum of x and y
function add(int256 x, int256 y) internal pure returns (int256 z) {
require((z = x + y) >= x == (y >= 0));
}
/// @notice Returns x - y, reverts if overflows or underflows
/// @param x The minuend
/// @param y The subtrahend
/// @return z The difference of x and y
function sub(int256 x, int256 y) internal pure returns (int256 z) {
require((z = x - y) <= x == (y >= 0));
}
/// @notice Returns x + y, reverts if overflows or underflows
/// @param x The augend
/// @param y The addend
/// @return z The sum of x and y
function add128(uint128 x, uint128 y) internal pure returns (uint128 z) {
require((z = x + y) >= x);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return price A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 price) {
// get abs value
int24 mask = tick >> (24 - 1);
uint256 absTick = uint256((tick ^ mask) - mask);
require(absTick <= uint256(MAX_TICK), 'T');
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
price = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case price < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param price The sqrt ratio for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint160 price) internal pure returns (int24 tick) {
// second inequality must be < because the price can never reach the price at the max tick
require(price >= MIN_SQRT_RATIO && price < MAX_SQRT_RATIO, 'R');
uint256 ratio = uint256(price) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= price ? tickHi : tickLow;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0 <0.8.0;
import '@cryptoalgebra/v1.9-core/contracts/libraries/FullMath.sol';
import '@cryptoalgebra/v1.9-core/contracts/libraries/TickMath.sol';
import '@cryptoalgebra/v1.9-core/contracts/interfaces/IAlgebraPool.sol';
import '@cryptoalgebra/v1.9-core/contracts/libraries/LowGasSafeMath.sol';
import '../libraries/PoolAddress.sol';
/// @title DataStorage library
/// @notice Provides functions to integrate with pool dataStorage
library DataStorageLibrary {
/// @notice Fetches time-weighted average tick using Algebra dataStorage
/// @param pool Address of Algebra pool that we want to getTimepoints
/// @param period Number of seconds in the past to start calculating time-weighted average
/// @return timeWeightedAverageTick The time-weighted average tick from (block.timestamp - period) to block.timestamp
function consult(address pool, uint32 period) internal view returns (int24 timeWeightedAverageTick) {
require(period != 0, 'BP');
uint32[] memory secondAgos = new uint32[](2);
secondAgos[0] = period;
secondAgos[1] = 0;
(int56[] memory tickCumulatives, , , ) = IAlgebraPool(pool).getTimepoints(secondAgos);
int56 tickCumulativesDelta = tickCumulatives[1] - tickCumulatives[0];
timeWeightedAverageTick = int24(tickCumulativesDelta / period);
// Always round to negative infinity
if (tickCumulativesDelta < 0 && (tickCumulativesDelta % period != 0)) timeWeightedAverageTick--;
}
/// @notice Given a tick and a token amount, calculates the amount of token received in exchange
/// @param tick Tick value used to calculate the quote
/// @param baseAmount Amount of token to be converted
/// @param baseToken Address of an ERC20 token contract used as the baseAmount denomination
/// @param quoteToken Address of an ERC20 token contract used as the quoteAmount denomination
/// @return quoteAmount Amount of quoteToken received for baseAmount of baseToken
function getQuoteAtTick(
int24 tick,
uint128 baseAmount,
address baseToken,
address quoteToken
) internal pure returns (uint256 quoteAmount) {
uint160 sqrtRatioX96 = TickMath.getSqrtRatioAtTick(tick);
// Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself
if (sqrtRatioX96 <= type(uint128).max) {
uint256 ratioX192 = uint256(sqrtRatioX96) * sqrtRatioX96;
quoteAmount = baseToken < quoteToken
? FullMath.mulDiv(ratioX192, baseAmount, 1 << 192)
: FullMath.mulDiv(1 << 192, baseAmount, ratioX192);
} else {
uint256 ratioX128 = FullMath.mulDiv(sqrtRatioX96, sqrtRatioX96, 1 << 64);
quoteAmount = baseToken < quoteToken
? FullMath.mulDiv(ratioX128, baseAmount, 1 << 128)
: FullMath.mulDiv(1 << 128, baseAmount, ratioX128);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import '@cryptoalgebra/v1.9-core/contracts/libraries/FullMath.sol';
import '@cryptoalgebra/v1.9-core/contracts/libraries/Constants.sol';
/// @title Liquidity amount functions
/// @notice Provides functions for computing liquidity amounts from token amounts and prices
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-periphery
library LiquidityAmounts {
/// @notice Downcasts uint256 to uint128
/// @param x The uint258 to be downcasted
/// @return y The passed value, downcasted to uint128
function toUint128(uint256 x) private pure returns (uint128 y) {
require((y = uint128(x)) == x);
}
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower))
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param amount0 The amount0 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount0(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, Constants.Q96);
return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96));
}
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param amount1 The amount1 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount1(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return toUint128(FullMath.mulDiv(amount1, Constants.Q96, sqrtRatioBX96 - sqrtRatioAX96));
}
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX96 A sqrt price representing the current pool prices
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param amount0 The amount of token0 being sent in
/// @param amount1 The amount of token1 being sent in
/// @return liquidity The maximum amount of liquidity received
function getLiquidityForAmounts(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0);
uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
} else {
liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1);
}
}
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
function getAmount0ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return
FullMath.mulDiv(uint256(liquidity) << Constants.RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96) /
sqrtRatioAX96;
}
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount1 The amount of token1
function getAmount1ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, Constants.Q96);
}
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current
/// pool prices and the prices at the tick boundaries
/// @param sqrtRatioX96 A sqrt price representing the current pool prices
/// @param sqrtRatioAX96 A sqrt price representing the first tick boundary
/// @param sqrtRatioBX96 A sqrt price representing the second tick boundary
/// @param liquidity The liquidity being valued
/// @return amount0 The amount of token0
/// @return amount1 The amount of token1
function getAmountsForLiquidity(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0, uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity);
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity);
} else {
amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Provides functions for deriving a pool address from the factory, tokens, and the fee
/// @dev Credit to Uniswap Labs under GPL-2.0-or-later license:
/// https://github.com/Uniswap/v3-periphery
library PoolAddress {
bytes32 internal constant POOL_INIT_CODE_HASH = 0xbce37a54eab2fcd71913a0d40723e04238970e7fc1159bfd58ad5b79531697e7;
/// @notice The identifying key of the pool
struct PoolKey {
address token0;
address token1;
}
/// @notice Returns PoolKey: the ordered tokens with the matched fee levels
/// @param tokenA The first token of a pool, unsorted
/// @param tokenB The second token of a pool, unsorted
/// @return Poolkey The pool details with ordered token0 and token1 assignments
function getPoolKey(address tokenA, address tokenB) internal pure returns (PoolKey memory) {
if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);
return PoolKey({token0: tokenA, token1: tokenB});
}
/// @notice Deterministically computes the pool address given the factory and PoolKey
/// @param factory The Algebra factory contract address
/// @param key The PoolKey
/// @return pool The contract address of the V3 pool
function computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {
require(key.token0 < key.token1);
pool = address(
uint256(
keccak256(
abi.encodePacked(
hex'ff',
factory,
keccak256(abi.encode(key.token0, key.token1)),
POOL_INIT_CODE_HASH
)
)
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}// 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, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
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) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
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, reverting 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) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* 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);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "../../utils/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 virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_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 virtual returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_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 virtual {
_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.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.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with 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;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @dev String operations.
*/
library Strings {
/**
* @dev Converts a `uint256` to its ASCII `string` representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
uint256 index = digits - 1;
temp = value;
while (temp != 0) {
buffer[index--] = bytes1(uint8(48 + temp % 10));
temp /= 10;
}
return string(buffer);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { UV3Math } from "./lib/UV3Math.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IAlgebraMintCallback } from "@cryptoalgebra/v1.9-core/contracts/interfaces/callback/IAlgebraMintCallback.sol";
import { IAlgebraSwapCallback } from "@cryptoalgebra/v1.9-core/contracts/interfaces/callback/IAlgebraSwapCallback.sol";
import { IAlgebraPool } from "@cryptoalgebra/v1.9-core/contracts/interfaces/IAlgebraPool.sol";
import { IDataStorageOperator } from "@cryptoalgebra/v1.9-core/contracts/interfaces/IDataStorageOperator.sol";
import { IICHIVault } from "../interfaces/IICHIVault.sol";
import { IICHIVaultFactory } from "../interfaces/IICHIVaultFactory.sol";
/**
@notice A Uniswap V2-like interface with fungible liquidity to Uniswap V3
which allows for either one-sided or two-sided liquidity provision.
ICHIVaults should be deployed by the ICHIVaultFactory.
ICHIVaults should not be used with tokens that charge transaction fees.
*/
contract ICHIVault is IICHIVault, IAlgebraMintCallback, IAlgebraSwapCallback, ERC20, ReentrancyGuard, Ownable {
using SafeERC20 for IERC20;
using SafeMath for uint256;
address public immutable override ichiVaultFactory;
address public immutable override pool;
address public immutable override token0;
address public immutable override token1;
bool public immutable override allowToken0;
bool public immutable override allowToken1;
address public override ammFeeRecipient;
address public override affiliate;
int24 public override baseLower;
int24 public override baseUpper;
int24 public override limitLower;
int24 public override limitUpper;
// The following three variables serve the very important purpose of
// limiting inventory risk and the arbitrage opportunities made possible by
// instant deposit & withdrawal.
// If, in the ETHUSDT pool at an ETH price of 2500 USDT, I deposit 100k
// USDT in a pool with 40 WETH, and then directly afterwards withdraw 50k
// USDT and 20 WETH (this is of equivalent dollar value), I drastically
// change the pool composition and additionally decreases deployed capital
// by 50%. Keeping a maxTotalSupply just above our current total supply
// means that large amounts of funds can't be deposited all at once to
// create a large imbalance of funds or to sideline many funds.
// Additionally, deposit maximums prevent users from using the pool as
// a counterparty to trade assets against while avoiding uniswap fees
// & slippage--if someone were to try to do this with a large amount of
// capital they would be overwhelmed by the gas fees necessary to call
// deposit & withdrawal many times.
uint256 public override deposit0Max;
uint256 public override deposit1Max;
uint256 public override maxTotalSupply;
uint256 public override hysteresis;
uint256 public constant PRECISION = 10 ** 18;
uint256 constant PERCENT = 100;
address constant NULL_ADDRESS = address(0);
uint32 public twapPeriod;
/**
@notice Creates ICHIVault for a pool, with controls for one-sided/two-sided liquidity.
@param _pool Uniswap V3 pool for liquidity management.
@param _allowToken0 If true, token0 is accepted for deposit.
@param _allowToken1 If true, token1 is accepted for deposit.
@param __owner Owner of the ICHIVault.
@param _twapPeriod TWAP period for hysteresis check.
@param _vaultIndex Vault index in the factory.
*/
constructor(
address _pool,
bool _allowToken0,
bool _allowToken1,
address __owner,
uint32 _twapPeriod,
uint256 _vaultIndex
) ERC20("ICHI Vault Liquidity", UV3Math.computeIVsymbol(_vaultIndex)) {
require(_pool != NULL_ADDRESS, "IV.constructor: zero address");
require(_allowToken0 || _allowToken1, "IV.constructor: no allowed tokens");
ichiVaultFactory = msg.sender;
pool = _pool;
token0 = IAlgebraPool(_pool).token0();
token1 = IAlgebraPool(_pool).token1();
allowToken0 = _allowToken0;
allowToken1 = _allowToken1;
twapPeriod = _twapPeriod;
transferOwnership(__owner);
maxTotalSupply = 0; // no cap
hysteresis = PRECISION.div(PERCENT); // 1% threshold
deposit0Max = uint256(-1); // max uint256
deposit1Max = uint256(-1); // max uint256
ammFeeRecipient = NULL_ADDRESS; // by default there is no amm fee recipient address;
affiliate = NULL_ADDRESS; // by default there is no affiliate address
emit DeployICHIVault(msg.sender, _pool, _allowToken0, _allowToken1, __owner, _twapPeriod);
}
function setTwapPeriod(uint32 newTwapPeriod) external onlyOwner {
require(newTwapPeriod > 0, "IV.setTwapPeriod: missing period");
twapPeriod = newTwapPeriod;
emit SetTwapPeriod(msg.sender, newTwapPeriod);
}
/**
@notice Distributes shares based on token1 value of deposit, total shares, and AUM in token1.
@param deposit0 Token0 amount transferred to ICHIVault.
@param deposit1 Token1 amount transferred to ICHIVault.
@param to Address for minting liquidity tokens.
@return shares Minted liquidity token quantity from deposit.
*/
function deposit(
uint256 deposit0,
uint256 deposit1,
address to
) external override nonReentrant returns (uint256 shares) {
require(allowToken0 || deposit0 == 0, "IV.deposit: token0 not allowed");
require(allowToken1 || deposit1 == 0, "IV.deposit: token1 not allowed");
require(deposit0 > 0 || deposit1 > 0, "IV.deposit: deposits must be > 0");
require(deposit0 < deposit0Max && deposit1 < deposit1Max, "IV.deposit: deposits too large");
require(to != NULL_ADDRESS && to != address(this), "IV.deposit: to");
// update fees for inclusion in total pool amounts
(uint128 baseLiquidity, , ) = _position(baseLower, baseUpper);
if (baseLiquidity > 0) {
(uint burn0, uint burn1) = IAlgebraPool(pool).burn(baseLower, baseUpper, 0);
require(burn0 == 0 && burn1 == 0, "IV.deposit: unexpected burn (1)");
}
(uint128 limitLiquidity, , ) = _position(limitLower, limitUpper);
if (limitLiquidity > 0) {
(uint burn0, uint burn1) = IAlgebraPool(pool).burn(limitLower, limitUpper, 0);
require(burn0 == 0 && burn1 == 0, "IV.deposit: unexpected burn (2)");
}
// Spot
uint256 price = _fetchSpot(token0, token1, currentTick(), PRECISION);
// TWAP
uint256 twap = _fetchTwap(pool, token0, token1, twapPeriod, PRECISION);
// if difference between spot and twap is too big, check if the price may have been manipulated in this block
uint256 delta = (price > twap)
? price.sub(twap).mul(PRECISION).div(price)
: twap.sub(price).mul(PRECISION).div(twap);
if (delta > hysteresis) require(checkHysteresis(), "IV.deposit: try later");
(uint256 pool0, uint256 pool1) = getTotalAmounts();
// aggregated deposit
uint256 deposit0PricedInToken1 = deposit0.mul((price < twap) ? price : twap).div(PRECISION);
if (deposit0 > 0) {
IERC20(token0).safeTransferFrom(msg.sender, address(this), deposit0);
}
if (deposit1 > 0) {
IERC20(token1).safeTransferFrom(msg.sender, address(this), deposit1);
}
shares = deposit1.add(deposit0PricedInToken1);
if (totalSupply() != 0) {
uint256 pool0PricedInToken1 = pool0.mul((price > twap) ? price : twap).div(PRECISION);
shares = shares.mul(totalSupply()).div(pool0PricedInToken1.add(pool1));
}
_mint(to, shares);
emit Deposit(msg.sender, to, shares, deposit0, deposit1);
// Check total supply cap not exceeded. A value of 0 means no limit.
require(maxTotalSupply == 0 || totalSupply() <= maxTotalSupply, "IV.deposit: maxTotalSupply");
}
/**
@notice Redeems shares for a portion of ICHIVault's AUM, based on share percentage.
@param shares Liquidity tokens number to redeem as pool assets.
@param to Address receiving the redeemed pool assets.
@return amount0 Token0 amount redeemed by the liquidity tokens.
@return amount1 Token1 amount redeemed by the liquidity tokens.
*/
function withdraw(
uint256 shares,
address to
) external override nonReentrant returns (uint256 amount0, uint256 amount1) {
require(shares > 0, "IV.withdraw: shares");
require(to != NULL_ADDRESS, "IV.withdraw: to");
// Withdraw liquidity from Uniswap pool
(uint256 base0, uint256 base1) = _burnLiquidity(
baseLower,
baseUpper,
_liquidityForShares(baseLower, baseUpper, shares),
to,
false
);
(uint256 limit0, uint256 limit1) = _burnLiquidity(
limitLower,
limitUpper,
_liquidityForShares(limitLower, limitUpper, shares),
to,
false
);
// Push tokens proportional to unused balances
uint256 _totalSupply = totalSupply();
uint256 unusedAmount0 = IERC20(token0).balanceOf(address(this)).mul(shares).div(_totalSupply);
uint256 unusedAmount1 = IERC20(token1).balanceOf(address(this)).mul(shares).div(_totalSupply);
if (unusedAmount0 > 0) IERC20(token0).safeTransfer(to, unusedAmount0);
if (unusedAmount1 > 0) IERC20(token1).safeTransfer(to, unusedAmount1);
amount0 = base0.add(limit0).add(unusedAmount0);
amount1 = base1.add(limit1).add(unusedAmount1);
_burn(msg.sender, shares);
emit Withdraw(msg.sender, to, shares, amount0, amount1);
}
/**
@notice Updates LP positions in ICHIVault.
@dev Places base position with max liquidity, typically symmetric around current price. Excess
from one token is placed in a single-sided order.
@param _baseLower Lower tick of the base position.
@param _baseUpper Upper tick of the base position.
@param _limitLower Lower tick of the limit position.
@param _limitUpper Upper tick of the limit position.
@param swapQuantity Token swap quantity; positive for token0 to token1, negative for reverse.
*/
function rebalance(
int24 _baseLower,
int24 _baseUpper,
int24 _limitLower,
int24 _limitUpper,
int256 swapQuantity
) external override nonReentrant onlyOwner {
int24 tickSpacing_ = IAlgebraPool(pool).tickSpacing();
require(
_baseLower < _baseUpper && _baseLower % tickSpacing_ == 0 && _baseUpper % tickSpacing_ == 0,
"IV.rebalance: base position invalid"
);
require(
_limitLower < _limitUpper && _limitLower % tickSpacing_ == 0 && _limitUpper % tickSpacing_ == 0,
"IV.rebalance: limit position invalid"
);
require(_baseLower != _limitLower || _baseUpper != _limitUpper, "IV.rebalance: identical positions");
// update fees
(uint128 baseLiquidity, , ) = _position(baseLower, baseUpper);
if (baseLiquidity > 0) {
IAlgebraPool(pool).burn(baseLower, baseUpper, 0);
}
(uint128 limitLiquidity, , ) = _position(limitLower, limitUpper);
if (limitLiquidity > 0) {
IAlgebraPool(pool).burn(limitLower, limitUpper, 0);
}
// Withdraw all liquidity and collect all fees from Uniswap pool
(, uint256 feesBase0, uint256 feesBase1) = _position(baseLower, baseUpper);
(, uint256 feesLimit0, uint256 feesLimit1) = _position(limitLower, limitUpper);
uint256 fees0 = feesBase0.add(feesLimit0);
uint256 fees1 = feesBase1.add(feesLimit1);
_burnLiquidity(baseLower, baseUpper, baseLiquidity, address(this), true);
_burnLiquidity(limitLower, limitUpper, limitLiquidity, address(this), true);
_distributeFees(fees0, fees1);
emit Rebalance(
currentTick(),
IERC20(token0).balanceOf(address(this)),
IERC20(token1).balanceOf(address(this)),
fees0,
fees1,
totalSupply()
);
// swap tokens if required
if (swapQuantity != 0) {
IAlgebraPool(pool).swap(
address(this),
swapQuantity > 0,
swapQuantity > 0 ? swapQuantity : -swapQuantity,
swapQuantity > 0 ? UV3Math.MIN_SQRT_RATIO + 1 : UV3Math.MAX_SQRT_RATIO - 1,
abi.encode(address(this))
);
}
baseLower = _baseLower;
baseUpper = _baseUpper;
baseLiquidity = _liquidityForAmounts(
baseLower,
baseUpper,
IERC20(token0).balanceOf(address(this)),
IERC20(token1).balanceOf(address(this))
);
_mintLiquidity(baseLower, baseUpper, baseLiquidity);
limitLower = _limitLower;
limitUpper = _limitUpper;
limitLiquidity = _liquidityForAmounts(
limitLower,
limitUpper,
IERC20(token0).balanceOf(address(this)),
IERC20(token1).balanceOf(address(this))
);
_mintLiquidity(limitLower, limitUpper, limitLiquidity);
}
/**
@notice Collects and distributes fees from ICHIVault's LP positions. Open to all for execution.
@return fees0 Collected fees in token0.
@return fees1 Collected fees in token1.
*/
function collectFees() external override nonReentrant returns (uint256 fees0, uint256 fees1) {
(uint128 baseLiquidity, , ) = _position(baseLower, baseUpper);
if (baseLiquidity > 0) {
(uint256 fee0, uint256 fee1) = _burnAnyLiquidity(
baseLower,
baseUpper,
0, // no liquidity is burned, only fees are colleted
address(this),
true
);
fees0 = fees0.add(fee0);
fees1 = fees1.add(fee1);
}
(uint128 limitLiquidity, , ) = _position(limitLower, limitUpper);
if (limitLiquidity > 0) {
(uint256 fee0, uint256 fee1) = _burnAnyLiquidity(
limitLower,
limitUpper,
0, // no liquidity is burned, only fees are colleted
address(this),
true
);
fees0 = fees0.add(fee0);
fees1 = fees1.add(fee1);
}
emit CollectFees(msg.sender, fees0, fees1);
if (fees0 > 0 || fees1 > 0) {
_distributeFees(fees0, fees1);
}
}
/**
@notice Sends portion of swap fees to ammFeeRecepient, feeRecipient and affiliate.
@param fees0 fees for token0
@param fees1 fees for token1
*/
function _distributeFees(uint256 fees0, uint256 fees1) internal {
uint256 ammFee = IICHIVaultFactory(ichiVaultFactory).ammFee();
uint256 baseFee = IICHIVaultFactory(ichiVaultFactory).baseFee();
// baseFeeRecipient cannot be NULL. This is checked and controlled in the factory
// ammFeeRecipient could be NULL, in this case ammFees are not taken
// ammFee + baseFee is always <= 100%. Also controlled in the factory
if (ammFee > 0 && ammFeeRecipient != NULL_ADDRESS) {
if (fees0 > 0) {
IERC20(token0).safeTransfer(ammFeeRecipient, fees0.mul(ammFee).div(PRECISION));
}
if (fees1 > 0) {
IERC20(token1).safeTransfer(ammFeeRecipient, fees1.mul(ammFee).div(PRECISION));
}
}
if (baseFee > 0) {
// if there is no affiliate 100% of the baseFee should go to feeRecipient
uint256 baseFeeSplit = (affiliate == NULL_ADDRESS)
? PRECISION
: IICHIVaultFactory(ichiVaultFactory).baseFeeSplit();
address feeRecipient = IICHIVaultFactory(ichiVaultFactory).feeRecipient();
if (fees0 > 0) {
uint256 totalFee = fees0.mul(baseFee).div(PRECISION);
uint256 toRecipient = totalFee.mul(baseFeeSplit).div(PRECISION);
uint256 toAffiliate = totalFee.sub(toRecipient);
IERC20(token0).safeTransfer(feeRecipient, toRecipient);
if (toAffiliate > 0) {
IERC20(token0).safeTransfer(affiliate, toAffiliate);
}
}
if (fees1 > 0) {
uint256 totalFee = fees1.mul(baseFee).div(PRECISION);
uint256 toRecipient = totalFee.mul(baseFeeSplit).div(PRECISION);
uint256 toAffiliate = totalFee.sub(toRecipient);
IERC20(token1).safeTransfer(feeRecipient, toRecipient);
if (toAffiliate > 0) {
IERC20(token1).safeTransfer(affiliate, toAffiliate);
}
}
}
}
/**
@notice Mint liquidity in Uniswap V3 pool.
@param tickLower The lower tick of the liquidity position
@param tickUpper The upper tick of the liquidity position
@param liquidity Amount of liquidity to mint
@return amount0 Used amount of token0
@return amount1 Used amount of token1
*/
function _mintLiquidity(
int24 tickLower,
int24 tickUpper,
uint128 liquidity
) internal returns (uint256 amount0, uint256 amount1) {
if (liquidity > 0) {
(amount0, amount1, ) = IAlgebraPool(pool).mint(
address(this),
address(this),
tickLower,
tickUpper,
liquidity,
abi.encode(address(this))
);
}
}
/**
@notice Burns Uniswap V3 pool liquidity.
@param tickLower Lower tick of the liquidity position.
@param tickUpper Upper tick of the liquidity position.
@param liquidity Liquidity amount to burn; must be >0, otherwise no action.
@param to Account receiving token0 and token1 from burn.
@param collectAll If true, collects all tokens; if false, only those from this burn.
@return amount0 Released amount of token0.
@return amount1 Released amount of token1.
*/
function _burnLiquidity(
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
address to,
bool collectAll
) internal returns (uint256 amount0, uint256 amount1) {
if (liquidity > 0) {
return _burnAnyLiquidity(tickLower, tickUpper, liquidity, to, collectAll);
}
}
/**
@notice Burns Uniswap V3 pool liquidity; collects fees if liquidity is zero.
@param tickLower Lower tick of the liquidity position.
@param tickUpper Upper tick of the liquidity position.
@param liquidity Liquidity amount to burn; can be zero.
@param to Account receiving token0 and token1 amounts.
@param collectAll If true, collects all tokens; otherwise, only from this burn.
@return amount0 Released amount of token0.
@return amount1 Released amount of token1.
*/
function _burnAnyLiquidity(
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
address to,
bool collectAll
) internal returns (uint256 amount0, uint256 amount1) {
// Burn liquidity
(uint256 owed0, uint256 owed1) = IAlgebraPool(pool).burn(tickLower, tickUpper, liquidity);
// Collect amount owed
uint128 collect0 = collectAll ? type(uint128).max : _uint128Safe(owed0);
uint128 collect1 = collectAll ? type(uint128).max : _uint128Safe(owed1);
if (collect0 > 0 || collect1 > 0) {
(amount0, amount1) = IAlgebraPool(pool).collect(to, tickLower, tickUpper, collect0, collect1);
}
}
/**
@notice Calculates liquidity amount for the given shares.
@param tickLower The lower tick of the liquidity position
@param tickUpper The upper tick of the liquidity position
@param shares number of shares
*/
function _liquidityForShares(int24 tickLower, int24 tickUpper, uint256 shares) internal view returns (uint128) {
(uint128 position, , ) = _position(tickLower, tickUpper);
return _uint128Safe(uint256(position).mul(shares).div(totalSupply()));
}
/**
@notice Returns information about the liquidity position.
@param tickLower The lower tick of the liquidity position
@param tickUpper The upper tick of the liquidity position
@return liquidity liquidity amount
@return tokensOwed0 amount of token0 owed to the owner of the position
@return tokensOwed1 amount of token1 owed to the owner of the position
*/
function _position(
int24 tickLower,
int24 tickUpper
) internal view returns (uint128 liquidity, uint128 tokensOwed0, uint128 tokensOwed1) {
bytes32 positionKey;
address owner = address(this);
assembly {
positionKey := or(shl(24, or(shl(24, owner), and(tickLower, 0xFFFFFF))), and(tickUpper, 0xFFFFFF))
}
(liquidity, , , , tokensOwed0, tokensOwed1) = IAlgebraPool(pool).positions(positionKey);
}
/**
@notice Callback function for mint
@dev this is where the payer transfers required token0 and token1 amounts
@param amount0 required amount of token0
@param amount1 required amount of token1
@param data encoded payer's address
*/
function algebraMintCallback(uint256 amount0, uint256 amount1, bytes calldata data) external override {
require(msg.sender == address(pool), "cb1");
address payer = abi.decode(data, (address));
if (payer == address(this)) {
if (amount0 > 0) IERC20(token0).safeTransfer(msg.sender, amount0);
if (amount1 > 0) IERC20(token1).safeTransfer(msg.sender, amount1);
} else {
if (amount0 > 0) IERC20(token0).safeTransferFrom(payer, msg.sender, amount0);
if (amount1 > 0) IERC20(token1).safeTransferFrom(payer, msg.sender, amount1);
}
}
/**
@notice Callback function for swap
@dev this is where the payer transfers required token0 and token1 amounts
@param amount0Delta required amount of token0
@param amount1Delta required amount of token1
@param data encoded payer's address
*/
function algebraSwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external override {
require(msg.sender == address(pool), "cb2");
address payer = abi.decode(data, (address));
if (amount0Delta > 0) {
if (payer == address(this)) {
IERC20(token0).safeTransfer(msg.sender, uint256(amount0Delta));
} else {
IERC20(token0).safeTransferFrom(payer, msg.sender, uint256(amount0Delta));
}
} else if (amount1Delta > 0) {
if (payer == address(this)) {
IERC20(token1).safeTransfer(msg.sender, uint256(amount1Delta));
} else {
IERC20(token1).safeTransferFrom(payer, msg.sender, uint256(amount1Delta));
}
}
}
/**
@notice Checks if the last price change happened in the current block
*/
function checkHysteresis() private view returns (bool) {
(, , , uint16 timepointIndex, , , ) = IAlgebraPool(pool).globalState();
address dataStorageOperator = IAlgebraPool(pool).dataStorageOperator();
(, uint32 blockTimestamp, , , , , ) = IDataStorageOperator(dataStorageOperator).timepoints(timepointIndex);
return (block.timestamp != blockTimestamp);
}
/**
@notice Returns the current fee in the pool
@return fee_ current fee in the pool
*/
function fee() external view override returns (uint24 fee_) {
(, , fee_, , , , ) = IAlgebraPool(pool).globalState();
}
/**
@notice Sets the maximum liquidity token supply the contract allows
@dev onlyOwner
@param _maxTotalSupply The maximum liquidity token supply the contract allows
*/
function setMaxTotalSupply(uint256 _maxTotalSupply) external onlyOwner {
maxTotalSupply = _maxTotalSupply;
emit MaxTotalSupply(msg.sender, _maxTotalSupply);
}
/**
@notice Sets hysteresis threshold (in percentage, 10**16 = 1%). Triggers check if spot vs TWAP
difference exceeds it.
@dev Only accessible by the owner.
@param _hysteresis New hysteresis threshold value.
*/
function setHysteresis(uint256 _hysteresis) external override onlyOwner {
hysteresis = _hysteresis;
emit Hysteresis(msg.sender, _hysteresis);
}
/**
@notice Sets the AMM fee recipient account address, where portion of the collected swap fees will be distributed
@dev onlyOwner
@param _ammFeeRecipient The AMM fee recipient account address
*/
function setAmmFeeRecipient(address _ammFeeRecipient) external override onlyOwner {
ammFeeRecipient = _ammFeeRecipient;
emit AmmFeeRecipient(msg.sender, _ammFeeRecipient);
}
/**
@notice Sets the affiliate account address where portion of the collected swap fees will be distributed
@dev onlyOwner
@param _affiliate The affiliate account address
*/
function setAffiliate(address _affiliate) external override onlyOwner {
affiliate = _affiliate;
emit Affiliate(msg.sender, _affiliate);
}
/**
@notice Sets the maximum token0 and token1 amounts the contract allows in a deposit
@dev onlyOwner
@param _deposit0Max The maximum amount of token0 allowed in a deposit
@param _deposit1Max The maximum amount of token1 allowed in a deposit
*/
function setDepositMax(uint256 _deposit0Max, uint256 _deposit1Max) external override onlyOwner {
deposit0Max = _deposit0Max;
deposit1Max = _deposit1Max;
emit DepositMax(msg.sender, _deposit0Max, _deposit1Max);
}
/**
@notice Calculates token0 and token1 amounts for liquidity in a position
@param tickLower The lower tick of the liquidity position
@param tickUpper The upper tick of the liquidity position
@param liquidity Amount of liquidity in the position
*/
function _amountsForLiquidity(
int24 tickLower,
int24 tickUpper,
uint128 liquidity
) internal view returns (uint256, uint256) {
(uint160 sqrtRatioX96, , , , , , ) = IAlgebraPool(pool).globalState();
return
UV3Math.getAmountsForLiquidity(
sqrtRatioX96,
UV3Math.getSqrtRatioAtTick(tickLower),
UV3Math.getSqrtRatioAtTick(tickUpper),
liquidity
);
}
/**
@notice Calculates amount of liquidity in a position for given token0 and token1 amounts
@param tickLower The lower tick of the liquidity position
@param tickUpper The upper tick of the liquidity position
@param amount0 token0 amount
@param amount1 token1 amount
*/
function _liquidityForAmounts(
int24 tickLower,
int24 tickUpper,
uint256 amount0,
uint256 amount1
) internal view returns (uint128) {
(uint160 sqrtRatioX96, , , , , , ) = IAlgebraPool(pool).globalState();
return
UV3Math.getLiquidityForAmounts(
sqrtRatioX96,
UV3Math.getSqrtRatioAtTick(tickLower),
UV3Math.getSqrtRatioAtTick(tickUpper),
amount0,
amount1
);
}
/**
@notice uint128Safe function
@param x input value
*/
function _uint128Safe(uint256 x) internal pure returns (uint128) {
require(x <= type(uint128).max, "IV.128_OF");
return uint128(x);
}
/**
@notice Returns the current tickSpacing in the pool
@return tickSpacing current tickSpacing in the pool
*/
function tickSpacing() external view override returns (int24) {
return IAlgebraPool(pool).tickSpacing();
}
/**
@notice Calculates total quantity of token0 and token1 in both positions (and unused in the ICHIVault)
@return total0 Quantity of token0 in both positions (and unused in the ICHIVault)
@return total1 Quantity of token1 in both positions (and unused in the ICHIVault)
*/
function getTotalAmounts() public view override returns (uint256 total0, uint256 total1) {
(, uint256 base0, uint256 base1) = getBasePosition();
(, uint256 limit0, uint256 limit1) = getLimitPosition();
total0 = IERC20(token0).balanceOf(address(this)).add(base0).add(limit0);
total1 = IERC20(token1).balanceOf(address(this)).add(base1).add(limit1);
}
/**
@notice Calculates amount of total liquidity in the base position
@return liquidity Amount of total liquidity in the base position
@return amount0 Estimated amount of token0 that could be collected by burning the base position
@return amount1 Estimated amount of token1 that could be collected by burning the base position
*/
function getBasePosition() public view returns (uint128 liquidity, uint256 amount0, uint256 amount1) {
(uint128 positionLiquidity, uint128 tokensOwed0, uint128 tokensOwed1) = _position(baseLower, baseUpper);
(amount0, amount1) = _amountsForLiquidity(baseLower, baseUpper, positionLiquidity);
liquidity = positionLiquidity;
amount0 = amount0.add(uint256(tokensOwed0));
amount1 = amount1.add(uint256(tokensOwed1));
}
/**
@notice Calculates amount of total liquidity in the limit position
@return liquidity Amount of total liquidity in the base position
@return amount0 Estimated amount of token0 that could be collected by burning the limit position
@return amount1 Estimated amount of token1 that could be collected by burning the limit position
*/
function getLimitPosition() public view returns (uint128 liquidity, uint256 amount0, uint256 amount1) {
(uint128 positionLiquidity, uint128 tokensOwed0, uint128 tokensOwed1) = _position(limitLower, limitUpper);
(amount0, amount1) = _amountsForLiquidity(limitLower, limitUpper, positionLiquidity);
liquidity = positionLiquidity;
amount0 = amount0.add(uint256(tokensOwed0));
amount1 = amount1.add(uint256(tokensOwed1));
}
/**
@notice Returns current price tick
@return tick Uniswap pool's current price tick
*/
function currentTick() public view returns (int24 tick) {
(, int24 tick_, , , , , bool unlocked_) = IAlgebraPool(pool).globalState();
require(unlocked_, "IV.currentTick: the pool is locked");
tick = tick_;
}
/**
@notice returns equivalent _tokenOut for _amountIn, _tokenIn using spot price
@param _tokenIn token the input amount is in
@param _tokenOut token for the output amount
@param _tick tick for the spot price
@param _amountIn amount in _tokenIn
@return amountOut equivalent anount in _tokenOut
*/
function _fetchSpot(
address _tokenIn,
address _tokenOut,
int24 _tick,
uint256 _amountIn
) internal pure returns (uint256 amountOut) {
return UV3Math.getQuoteAtTick(_tick, UV3Math.toUint128(_amountIn), _tokenIn, _tokenOut);
}
/**
@notice returns equivalent _tokenOut for _amountIn, _tokenIn using TWAP price
@param _pool Uniswap V3 pool address to be used for price checking
@param _tokenIn token the input amount is in
@param _tokenOut token for the output amount
@param _twapPeriod the averaging time period
@param _amountIn amount in _tokenIn
@return amountOut equivalent anount in _tokenOut
*/
function _fetchTwap(
address _pool,
address _tokenIn,
address _tokenOut,
uint32 _twapPeriod,
uint256 _amountIn
) internal view returns (uint256 amountOut) {
// Leave twapTick as a int256 to avoid solidity casting
int256 twapTick = UV3Math.consult(_pool, _twapPeriod);
return
UV3Math.getQuoteAtTick(
int24(twapTick), // can assume safe being result from consult()
UV3Math.toUint128(_amountIn),
_tokenIn,
_tokenOut
);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
import { TickMath } from "@cryptoalgebra/v1.9-core/contracts/libraries/TickMath.sol";
import { LiquidityAmounts } from "@cryptoalgebra/v1.9-periphery/contracts/libraries/LiquidityAmounts.sol";
import { DataStorageLibrary } from "@cryptoalgebra/v1.9-periphery/contracts/libraries/DataStorageLibrary.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
library UV3Math {
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/*******************
* Tick Math
*******************/
function getSqrtRatioAtTick(int24 currentTick) public pure returns (uint160 sqrtPriceX96) {
sqrtPriceX96 = TickMath.getSqrtRatioAtTick(currentTick);
}
/*******************
* LiquidityAmounts
*******************/
function getAmountsForLiquidity(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) public pure returns (uint256 amount0, uint256 amount1) {
(amount0, amount1) = LiquidityAmounts.getAmountsForLiquidity(
sqrtRatioX96,
sqrtRatioAX96,
sqrtRatioBX96,
liquidity
);
}
function getLiquidityForAmounts(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0,
uint256 amount1
) public pure returns (uint128 liquidity) {
liquidity = LiquidityAmounts.getLiquidityForAmounts(
sqrtRatioX96,
sqrtRatioAX96,
sqrtRatioBX96,
amount0,
amount1
);
}
/*******************
* OracleLibrary
*******************/
function consult(address _pool, uint32 _twapPeriod) public view returns (int24 timeWeightedAverageTick) {
timeWeightedAverageTick = DataStorageLibrary.consult(_pool, _twapPeriod);
}
function getQuoteAtTick(
int24 tick,
uint128 baseAmount,
address baseToken,
address quoteToken
) public pure returns (uint256 quoteAmount) {
quoteAmount = DataStorageLibrary.getQuoteAtTick(tick, baseAmount, baseToken, quoteToken);
}
/*******************
* SafeUnit128
*******************/
/// @notice Cast a uint256 to a uint128, revert on overflow
/// @param y The uint256 to be downcasted
/// @return z The downcasted integer, now type uint128
function toUint128(uint256 y) public pure returns (uint128 z) {
require((z = uint128(y)) == y, "SafeUint128: overflow");
}
/******************************
* ICHIVault specific functions
******************************/
/**
@dev Computes a unique vault's symbol for vaults created through Ramses factory.
@param value index of the vault to be created
*/
function computeIVsymbol(uint256 value) public pure returns (string memory) {
return string(abi.encodePacked("IV-", Strings.toString(value), "-LYNX"));
}
}// SPDX-License-Identifier: Unlicense
pragma solidity 0.7.6;
interface IICHIVault {
function ichiVaultFactory() external view returns (address);
function pool() external view returns (address);
function token0() external view returns (address);
function allowToken0() external view returns (bool);
function token1() external view returns (address);
function allowToken1() external view returns (bool);
function fee() external view returns (uint24);
function tickSpacing() external view returns (int24);
function ammFeeRecipient() external view returns (address);
function affiliate() external view returns (address);
function baseLower() external view returns (int24);
function baseUpper() external view returns (int24);
function limitLower() external view returns (int24);
function limitUpper() external view returns (int24);
function deposit0Max() external view returns (uint256);
function deposit1Max() external view returns (uint256);
function maxTotalSupply() external view returns (uint256);
function hysteresis() external view returns (uint256);
function getTotalAmounts() external view returns (uint256, uint256);
function deposit(uint256, uint256, address) external returns (uint256);
function withdraw(uint256, address) external returns (uint256, uint256);
function rebalance(
int24 _baseLower,
int24 _baseUpper,
int24 _limitLower,
int24 _limitUpper,
int256 swapQuantity
) external;
function collectFees() external returns (uint256 fees0, uint256 fees1);
function setDepositMax(uint256 _deposit0Max, uint256 _deposit1Max) external;
function setHysteresis(uint256 _hysteresis) external;
function setAmmFeeRecipient(address _ammFeeRecipient) external;
function setAffiliate(address _affiliate) external;
event DeployICHIVault(
address indexed sender,
address indexed pool,
bool allowToken0,
bool allowToken1,
address owner,
uint256 twapPeriod
);
event SetTwapPeriod(address sender, uint32 newTwapPeriod);
event Deposit(address indexed sender, address indexed to, uint256 shares, uint256 amount0, uint256 amount1);
event Withdraw(address indexed sender, address indexed to, uint256 shares, uint256 amount0, uint256 amount1);
event Rebalance(
int24 tick,
uint256 totalAmount0,
uint256 totalAmount1,
uint256 feeAmount0,
uint256 feeAmount1,
uint256 totalSupply
);
event CollectFees(address indexed sender, uint256 feeAmount0, uint256 feeAmount1);
event MaxTotalSupply(address indexed sender, uint256 maxTotalSupply);
event Hysteresis(address indexed sender, uint256 hysteresis);
event DepositMax(address indexed sender, uint256 deposit0Max, uint256 deposit1Max);
event AmmFeeRecipient(address indexed sender, address ammFeeRecipient);
event Affiliate(address indexed sender, address affiliate);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.7.6;
interface IICHIVaultFactory {
event FeeRecipient(address indexed sender, address feeRecipient);
event AmmFee(address indexed sender, uint256 ammFee);
event BaseFee(address indexed sender, uint256 baseFee);
event BaseFeeSplit(address indexed sender, uint256 baseFeeSplit);
event DeployICHIVaultFactory(address indexed sender, address algebraFactory);
event ICHIVaultCreated(
address indexed sender,
address ichiVault,
address tokenA,
bool allowTokenA,
address tokenB,
bool allowTokenB,
uint256 count
);
function algebraFactory() external view returns (address);
function feeRecipient() external view returns (address);
function ammFee() external view returns (uint256);
function baseFee() external view returns (uint256);
function baseFeeSplit() external view returns (uint256);
function setFeeRecipient(address _feeRecipient) external;
function setAmmFee(uint256 _ammFee) external;
function setBaseFee(uint256 _baseFee) external;
function setBaseFeeSplit(uint256 _baseFeeSplit) external;
function createICHIVault(
address tokenA,
bool allowTokenA,
address tokenB,
bool allowTokenB
) external returns (address ichiVault);
function genKey(
address deployer,
address token0,
address token1,
bool allowToken0,
bool allowToken1
) external pure returns (bytes32 key);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"contracts/lib/UV3Math.sol": {
"UV3Math": "0xa7e0fb32618818cfcaba025a3af3544c17ca84f6"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract Creation Code
615dfd610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063ade6c30a1461003a575b600080fd5b81801561004657600080fd5b506100a1600480360360e081101561005d57600080fd5b506001600160a01b03813581169160208101358216916040820135151591606081013590911690608081013515159063ffffffff60a0820135169060c001356100bd565b604080516001600160a01b039092168252519081900360200190f35b6000338787878760405160200180866001600160a01b031660601b8152601401856001600160a01b031660601b815260140184151560f81b8152600101836001600160a01b031660601b815260140182151560f81b81526001019550505050505060405160208183030381529060405280519060200120888786338787604051610146906101b1565b6001600160a01b039687168152941515602086015292151560408086019190915291909416606084015263ffffffff909316608083015260a08201529051829181900360c001906000f59050801580156101a4573d6000803e3d6000fd5b5098975050505050505050565b615c09806101bf8339019056fe6101406040523480156200001257600080fd5b5060405162005c0938038062005c09833981810160405260c08110156200003857600080fd5b5080516020808301516040808501516060860151608087015160a09097015183518085018552601481527f49434849205661756c74204c6971756964697479000000000000000000000000968101969096528351639c6dde5360e01b8152600481018290529351969794969295919493909273a7e0fb32618818cfcaba025a3af3544c17ca84f691639c6dde53916024808301926000929190829003018186803b158015620000e657600080fd5b505af4158015620000fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156200012557600080fd5b81019080805160405193929190846401000000008211156200014657600080fd5b9083019060208201858111156200015c57600080fd5b82516401000000008111828201881017156200017757600080fd5b82525081516020918201929091019080838360005b83811015620001a65781810151838201526020016200018c565b50505050905090810190601f168015620001d45780820380516001836020036101000a031916815260200191505b5060405250508251620001f09150600390602085019062000695565b5080516200020690600490602084019062000695565b50506005805460ff191660121790555060016006556000620002276200050e565b600780546001600160a01b0319166001600160a01b0383169081179091556040519192509060009060008051602062005bc8833981519152908290a3506001600160a01b038616620002c0576040805162461bcd60e51b815260206004820152601c60248201527f49562e636f6e7374727563746f723a207a65726f206164647265737300000000604482015290519081900360640190fd5b8480620002ca5750835b620003075760405162461bcd60e51b815260040180806020018281038252602181526020018062005be86021913960400191505060405180910390fd5b33606090811b60805286901b6001600160601b03191660a05260408051630dfe168160e01b815290516001600160a01b03881691630dfe1681916004808301926020929190829003018186803b1580156200036157600080fd5b505afa15801562000376573d6000803e3d6000fd5b505050506040513d60208110156200038d57600080fd5b505160601b6001600160601b03191660c0526040805163d21220a760e01b815290516001600160a01b0388169163d21220a7916004808301926020929190829003018186803b158015620003e057600080fd5b505afa158015620003f5573d6000803e3d6000fd5b505050506040513d60208110156200040c57600080fd5b505160601b6001600160601b03191660e05284151560f890811b61010052841515901b61012052600e805463ffffffff191663ffffffff8416179055620004538362000512565b6000600c5562000479670de0b6b3a764000060646200061d602090811b620033bc17901c565b600d55600019600a819055600b55600880546001600160a01b031990811690915560098054909116905560408051861515815285151560208201526001600160a01b038581168284015263ffffffff8516606083015291519188169133917f3e708ccf7d0e6de8558e020ea36189511cb3435bbfec54e721a48ee4df0d4f8c919081900360800190a350505050505062000741565b3390565b6200051c6200050e565b6001600160a01b03166200052f62000686565b6001600160a01b0316146200058b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116620005d25760405162461bcd60e51b815260040180806020018281038252602681526020018062005ba26026913960400191505060405180910390fd5b6007546040516001600160a01b0380841692169060008051602062005bc883398151915290600090a3600780546001600160a01b0319166001600160a01b0392909216919091179055565b600080821162000674576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816200067e57fe5b049392505050565b6007546001600160a01b031690565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282620006cd576000855562000718565b82601f10620006e857805160ff191683800117855562000718565b8280016001018555821562000718579182015b8281111562000718578251825591602001919060010190620006fb565b50620007269291506200072a565b5090565b5b808211156200072657600081556001016200072b565b60805160601c60a05160601c60c05160601c60e05160601c6101005160f81c6101205160f81c6152e8620008ba6000398061115852806117f35250806116205280611778525080610b0c5280610bc652806110ea528061111e528061129f52806113145280611c825280611d0a5280611e6b528061222452806124e05280612b955280612ef852806146a6528061491b5280614959525080610a5b5280610b8c5280610e11528061105d5280611096528061126552806112d95280611c615280611ce85280611e30528061217b5280612b035280612e4152806130005280614649528061485b5280614899525080610c875280610e455280610fbf52806111d35280611a1a5280611b7e5280611cc65280612456528061260f5280612867528061295e5280612c5852806130fb52806139fd5280613dff5280613ea5528061409e5280614316528061444252806149935280614c445250806130d552806144de528061458152806146e9528061478152506152e86000f3fe608060405234801561001057600080fd5b50600436106102d55760003560e01c80637aea530911610182578063c4a7761e116100e9578063dd62ed3e116100a2578063f2fde38b1161007c578063f2fde38b1461087b578063f6207326146108a1578063f9c95d46146108c2578063fa082743146108e5576102d5565b8063dd62ed3e14610825578063dd81fa6314610853578063ddca3f431461085b576102d5565b8063c4a7761e146107bc578063c8796572146107c4578063d0c93a7c146107cc578063d21220a7146107d4578063d2eabcfc146107dc578063d87346aa146107e4576102d5565b80638dbdbe6d1161013b5780638dbdbe6d146106f257806395d89b4114610724578063a049de6b1461072c578063a457c2d71461075c578063a9059cbb14610788578063aaf5eb68146107b4576102d5565b80637aea5309146106a45780637f7a1eec146106ac57806381de128b146106b4578063888a9134146106da578063897f078c146106e25780638da5cb5b146106ea576102d5565b8063313ce5671161024157806345e05f43116101fa5780635ffc1ff7116101d45780635ffc1ff714610651578063648cab851461066e57806370a0823114610676578063715018a61461069c576102d5565b806345e05f43146106395780634d461fbb1461064157806351e87af714610649576102d5565b8063313ce5671461052b57806337e41b401461054957806339509351146105515780633dd657c51461057d5780633e091ee9146105f95780633f3e4c111461061c576102d5565b806316f0115b1161029357806316f0115b1461042757806318160ddd1461042f57806323b872dd146104495780632ab4d0521461047f5780632bbb56d9146104875780632c8958f6146104af576102d5565b8062f714ce146102da578063065e53601461031f57806306fdde031461033e578063095ea7b3146103bb5780630dfe1681146103fb5780630f35bcac1461041f575b600080fd5b610306600480360360408110156102f057600080fd5b50803590602001356001600160a01b03166108ed565b6040805192835260208301919091528051918290030190f35b610327610c80565b6040805160029290920b8252519081900360200190f35b610346610d5b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610380578181015183820152602001610368565b50505050905090810190601f1680156103ad5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103e7600480360360408110156103d157600080fd5b506001600160a01b038135169060200135610df1565b604080519115158252519081900360200190f35b610403610e0f565b604080516001600160a01b039092168252519081900360200190f35b610327610e33565b610403610e43565b610437610e67565b60408051918252519081900360200190f35b6103e76004803603606081101561045f57600080fd5b506001600160a01b03813581169160208101359091169060400135610e6d565b610437610ef5565b6104ad6004803603602081101561049d57600080fd5b50356001600160a01b0316610efb565b005b6104ad600480360360608110156104c557600080fd5b8135916020810135918101906060810160408201356401000000008111156104ec57600080fd5b8201836020820111156104fe57600080fd5b8035906020019184600183028401116401000000008311171561052057600080fd5b509092509050610fb4565b61053361114d565b6040805160ff9092168252519081900360200190f35b6103e7611156565b6103e76004803603604081101561056757600080fd5b506001600160a01b03813516906020013561117a565b6104ad6004803603606081101561059357600080fd5b8135916020810135918101906060810160408201356401000000008111156105ba57600080fd5b8201836020820111156105cc57600080fd5b803590602001918460018302840111640100000000831117156105ee57600080fd5b5090925090506111c8565b6104ad6004803603604081101561060f57600080fd5b508035906020013561133c565b6104ad6004803603602081101561063257600080fd5b50356113e6565b610403611486565b610437611495565b61032761149b565b6104ad6004803603602081101561066757600080fd5b50356114ab565b61043761154b565b6104376004803603602081101561068c57600080fd5b50356001600160a01b0316611551565b6104ad61156c565b610437611618565b6103e761161e565b6104ad600480360360208110156106ca57600080fd5b50356001600160a01b0316611642565b6103276116fb565b61040361170b565b61040361171a565b6104376004803603606081101561070857600080fd5b50803590602081013590604001356001600160a01b0316611729565b610346611fcd565b61073461202e565b604080516001600160801b039094168452602084019290925282820152519081900360600190f35b6103e76004803603604081101561077257600080fd5b506001600160a01b0381351690602001356120c6565b6103e76004803603604081101561079e57600080fd5b506001600160a01b03813516906020013561212e565b610437612142565b61030661214e565b610306612299565b610327612452565b6104036124de565b610734612502565b6104ad600480360360a08110156107fa57600080fd5b508035600290810b916020810135820b916040820135810b91606081013590910b906080013561255e565b6104376004803603604081101561083b57600080fd5b506001600160a01b03813581169160200135166130a8565b6104036130d3565b6108636130f7565b6040805162ffffff9092168252519081900360200190f35b6104ad6004803603602081101561089157600080fd5b50356001600160a01b031661318a565b6108a961328d565b6040805163ffffffff9092168252519081900360200190f35b6104ad600480360360208110156108d857600080fd5b503563ffffffff16613299565b6103276133ac565b60008060026006541415610936576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b600260065583610983576040805162461bcd60e51b815260206004820152601360248201527249562e77697468647261773a2073686172657360681b604482015290519081900360640190fd5b6001600160a01b0383166109d0576040805162461bcd60e51b815260206004820152600f60248201526e49562e77697468647261773a20746f60881b604482015290519081900360640190fd5b6009546000908190610a0590600160a01b8104600290810b91600160b81b9004900b6109fd82828b613423565b886000613463565b60095491935091506000908190610a3f90600160d01b8104600290810b91600160e81b9004900b610a3782828d613423565b8a6000613463565b915091506000610a4d610e67565b90506000610afe82610af88c7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610ac657600080fd5b505afa158015610ada573d6000803e3d6000fd5b505050506040513d6020811015610af057600080fd5b505190613491565b906133bc565b90506000610b7783610af88d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610ac657600080fd5b90508115610bb357610bb36001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b846134ea565b8015610bed57610bed6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b836134ea565b610c0182610bfb8988613541565b90613541565b9850610c1181610bfb8887613541565b9750610c1d338c61359b565b604080518c8152602081018b90528082018a905290516001600160a01b038c169133917febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f9181900360600190a35050505050505060016006819055509250929050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015610cde57600080fd5b505afa158015610cf2573d6000803e3d6000fd5b505050506040513d60e0811015610d0857600080fd5b50602081015160c090910151909250905080610d555760405162461bcd60e51b815260040180806020018281038252602281526020018061512a6022913960400191505060405180910390fd5b50919050565b60038054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610de75780601f10610dbc57610100808354040283529160200191610de7565b820191906000526020600020905b815481529060010190602001808311610dca57829003601f168201915b5050505050905090565b6000610e05610dfe613697565b848461369b565b5060015b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600954600160e81b900460020b81565b7f000000000000000000000000000000000000000000000000000000000000000081565b60025490565b6000610e7a848484613787565b610eea84610e86613697565b610ee58560405180606001604052806028815260200161516d602891396001600160a01b038a16600090815260016020526040812090610ec4613697565b6001600160a01b0316815260208101919091526040016000205491906138e2565b61369b565b5060015b9392505050565b600c5481565b610f03613697565b6001600160a01b0316610f1461171a565b6001600160a01b031614610f5d576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600980546001600160a01b0383166001600160a01b03199091168117909155604080519182525133917f3066ef5dd340e8b2ea28d62f5a8391eb7a82d3ee87532724a1ca4386d34f7523919081900360200190a250565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611017576040805162461bcd60e51b815260206004820152600360248201526231b11960e91b604482015290519081900360640190fd5b60008282602081101561102957600080fd5b50356001600160a01b0316905060008513156110c3576001600160a01b038116301415611089576110846001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633876134ea565b6110be565b6110be6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823388613979565b611146565b6000841315611146576001600160a01b038116301415611111576110be6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633866134ea565b6111466001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823387613979565b5050505050565b60055460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610e05611187613697565b84610ee58560016000611198613697565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490613541565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461122b576040805162461bcd60e51b815260206004820152600360248201526263623160e81b604482015290519081900360640190fd5b60008282602081101561123d57600080fd5b50356001600160a01b03169050308114156112c657841561128c5761128c6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633876134ea565b83156110be576110be6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633866134ea565b8415611301576113016001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823388613979565b8315611146576111466001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823387613979565b611344613697565b6001600160a01b031661135561171a565b6001600160a01b03161461139e576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600a829055600b8190556040805183815260208101839052815133927fafd3b05a4086b378b6f291200a528d8aed8c5e0317af77436b001f1bec28821a928290030190a25050565b6113ee613697565b6001600160a01b03166113ff61171a565b6001600160a01b031614611448576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600c81905560408051828152905133917f7423cea36ad2104e8e8c3d9aa1e24288bdf3bfa7b4f37868cfa6d4d34ffdaf3a919081900360200190a250565b6009546001600160a01b031681565b600b5481565b600954600160d01b900460020b81565b6114b3613697565b6001600160a01b03166114c461171a565b6001600160a01b03161461150d576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600d81905560408051828152905133917f529698f34660760dcb172def5c99d62e1b5b74b444df322e8f7da31f2bd0a86b919081900360200190a250565b600a5481565b6001600160a01b031660009081526020819052604090205490565b611574613697565b6001600160a01b031661158561171a565b6001600160a01b0316146115ce576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b6007546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600780546001600160a01b0319169055565b600d5481565b7f000000000000000000000000000000000000000000000000000000000000000081565b61164a613697565b6001600160a01b031661165b61171a565b6001600160a01b0316146116a4576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600880546001600160a01b0383166001600160a01b03199091168117909155604080519182525133917fbb78b7c13893a913fa8c9ecb9fdaf97597aa412a39c778bf976790555f0942f7919081900360200190a250565b600954600160b81b900460020b81565b6008546001600160a01b031681565b6007546001600160a01b031690565b600060026006541415611771576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b60026006557f0000000000000000000000000000000000000000000000000000000000000000806117a0575083155b6117f1576040805162461bcd60e51b815260206004820152601e60248201527f49562e6465706f7369743a20746f6b656e30206e6f7420616c6c6f7765640000604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000008061181b575082155b61186c576040805162461bcd60e51b815260206004820152601e60248201527f49562e6465706f7369743a20746f6b656e31206e6f7420616c6c6f7765640000604482015290519081900360640190fd5b600084118061187b5750600083115b6118cc576040805162461bcd60e51b815260206004820181905260248201527f49562e6465706f7369743a206465706f73697473206d757374206265203e2030604482015290519081900360640190fd5b600a54841080156118de5750600b5483105b61192f576040805162461bcd60e51b815260206004820152601e60248201527f49562e6465706f7369743a206465706f7369747320746f6f206c617267650000604482015290519081900360640190fd5b6001600160a01b0382161580159061195057506001600160a01b0382163014155b611992576040805162461bcd60e51b815260206004820152600e60248201526d49562e6465706f7369743a20746f60901b604482015290519081900360640190fd5b6009546000906119b790600160a01b8104600290810b91600160b81b9004900b6139d9565b50909150506001600160801b03811615611af6576009546040805163a34123a760e01b8152600160a01b8304600290810b810b6004830152600160b81b909304830b90920b60248301526000604483018190528151909283926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a34123a792606480820193929182900301818787803b158015611a5e57600080fd5b505af1158015611a72573d6000803e3d6000fd5b505050506040513d6040811015611a8857600080fd5b508051602090910151909250905081158015611aa2575080155b611af3576040805162461bcd60e51b815260206004820152601f60248201527f49562e6465706f7369743a20756e6578706563746564206275726e2028312900604482015290519081900360640190fd5b50505b600954600090611b1b90600160d01b8104600290810b91600160e81b9004900b6139d9565b50909150506001600160801b03811615611c5a576009546040805163a34123a760e01b8152600160d01b8304600290810b810b6004830152600160e81b909304830b90920b60248301526000604483018190528151909283926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a34123a792606480820193929182900301818787803b158015611bc257600080fd5b505af1158015611bd6573d6000803e3d6000fd5b505050506040513d6040811015611bec57600080fd5b508051602090910151909250905081158015611c06575080155b611c57576040805162461bcd60e51b815260206004820152601f60248201527f49562e6465706f7369743a20756e6578706563746564206275726e2028322900604482015290519081900360640190fd5b50505b6000611cb77f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611ca9610c80565b670de0b6b3a7640000613aa6565b600e54909150600090611d3e907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff16670de0b6b3a7640000613bda565b90506000818311611d6e57611d6982610af8670de0b6b3a7640000611d638388613d9d565b90613491565b611d88565b611d8883610af8670de0b6b3a7640000611d638387613d9d565b9050600d54811115611de557611d9c613dfa565b611de5576040805162461bcd60e51b815260206004820152601560248201527424ab173232b837b9b4ba1d103a393c903630ba32b960591b604482015290519081900360640190fd5b600080611df061214e565b915091506000611e1b670de0b6b3a7640000610af8878910611e125787611e14565b885b8f90613491565b90508b15611e5857611e586001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308f613979565b8a15611e9357611e936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308e613979565b611e9d8b82613541565b9850611ea7610e67565b15611ef8576000611ed3670de0b6b3a7640000610af8888a11611eca5788611ecc565b895b8790613491565b9050611ef4611ee28285613541565b610af8611eed610e67565b8d90613491565b9950505b611f028a8a613fa7565b604080518a8152602081018e90528082018d905290516001600160a01b038c169133917f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f69181900360600190a3600c541580611f675750600c54611f64610e67565b11155b611fb8576040805162461bcd60e51b815260206004820152601a60248201527f49562e6465706f7369743a206d6178546f74616c537570706c79000000000000604482015290519081900360640190fd5b50506001600655509498975050505050505050565b60048054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610de75780601f10610dbc57610100808354040283529160200191610de7565b60008060008060008061205f6009601a9054906101000a900460020b6009601d9054906101000a900460020b6139d9565b600954929550909350915061208a90600160d01b8104600290810b91600160e81b9004900b85614097565b939650945091925084916120a7856001600160801b038416613541565b94506120bc846001600160801b038316613541565b9350505050909192565b6000610e056120d3613697565b84610ee58560405180606001604052806025815260200161528e60259139600160006120fd613697565b6001600160a01b03908116825260208083019390935260409182016000908120918d168152925290205491906138e2565b6000610e0561213b613697565b8484613787565b670de0b6b3a764000081565b60008060008061215c612502565b925092505060008061216c61202e565b925092505061221882610bfb867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156121e657600080fd5b505afa1580156121fa573d6000803e3d6000fd5b505050506040513d602081101561221057600080fd5b505190613541565b955061228f81610bfb857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156121e657600080fd5b9450505050509091565b600080600260065414156122e2576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b6002600681905560095460009161230c91600160a01b8104820b91600160b81b909104900b6139d9565b50909150506001600160801b0381161561236b57600954600090819061234b90600160a01b8104600290810b91600160b81b9004900b833060016142d2565b909250905061235a8583613541565b94506123668482613541565b935050505b60095460009061239090600160d01b8104600290810b91600160e81b9004900b6139d9565b50909150506001600160801b038116156123ef5760095460009081906123cf90600160d01b8104600290810b91600160e81b9004900b833060016142d2565b90925090506123de8683613541565b95506123ea8582613541565b945050505b6040805185815260208101859052815133927fec8208dd791fa8ffdc0d7427f3ba9c0ed06f1bce9a86254e6940c10cc1802fef928290030190a260008411806124385750600083115b156124475761244784846144da565b505060016006559091565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0c93a7c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156124ad57600080fd5b505afa1580156124c1573d6000803e3d6000fd5b505050506040513d60208110156124d757600080fd5b5051905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080600080600080612533600960149054906101000a900460020b600960179054906101000a900460020b6139d9565b600954929550909350915061208a90600160a01b8104600290810b91600160b81b9004900b85614097565b600260065414156125a4576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b60026006556125b1613697565b6001600160a01b03166125c261171a565b6001600160a01b03161461260b576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0c93a7c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561266657600080fd5b505afa15801561267a573d6000803e3d6000fd5b505050506040513d602081101561269057600080fd5b50519050600285810b9087900b1280156126ba57508060020b8660020b816126b457fe5b0760020b155b80156126d657508060020b8560020b816126d057fe5b0760020b155b6127115760405162461bcd60e51b81526004018080602001828103825260238152602001806150bb6023913960400191505060405180910390fd5b8260020b8460020b12801561273657508060020b8460020b8161273057fe5b0760020b155b801561275257508060020b8360020b8161274c57fe5b0760020b155b61278d5760405162461bcd60e51b815260040180806020018281038252602481526020018061526a6024913960400191505060405180910390fd5b8360020b8660020b1415806127a857508260020b8560020b14155b6127e35760405162461bcd60e51b815260040180806020018281038252602181526020018061521f6021913960400191505060405180910390fd5b60095460009061280890600160a01b8104600290810b91600160b81b9004900b6139d9565b50909150506001600160801b038116156128da576009546040805163a34123a760e01b8152600160a01b8304600290810b810b6004830152600160b81b909304830b90920b602483015260006044830181905281516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363a34123a7936064808301949193928390030190829087803b1580156128ad57600080fd5b505af11580156128c1573d6000803e3d6000fd5b505050506040513d60408110156128d757600080fd5b50505b6009546000906128ff90600160d01b8104600290810b91600160e81b9004900b6139d9565b50909150506001600160801b038116156129d1576009546040805163a34123a760e01b8152600160d01b8304600290810b810b6004830152600160e81b909304830b90920b602483015260006044830181905281516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363a34123a7936064808301949193928390030190829087803b1580156129a457600080fd5b505af11580156129b8573d6000803e3d6000fd5b505050506040513d60408110156129ce57600080fd5b50505b60095460009081906129f890600160a01b8104600290810b91600160b81b9004900b6139d9565b6009546001600160801b03928316955091169250600091508190612a3190600160d01b8104600290810b91600160e81b9004900b6139d9565b6001600160801b03918216945016915060009050612a4f8584613541565b90506000612a5d8584613541565b600954909150612a8690600160a01b8104600290810b91600160b81b9004900b8a306001613463565b5050600954612aae90600160d01b8104600290810b91600160e81b9004900b89306001613463565b5050612aba82826144da565b7fbc4c20ad04f161d631d9ce94d27659391196415aa3c42f6a71c62e905ece782d612ae3610c80565b604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015612b4957600080fd5b505afa158015612b5d573d6000803e3d6000fd5b505050506040513d6020811015612b7357600080fd5b5051604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015612bdb57600080fd5b505afa158015612bef573d6000803e3d6000fd5b505050506040513d6020811015612c0557600080fd5b50518585612c11610e67565b6040805160029790970b87526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190a18915612dd8576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663128acb083060008d1380612c90578d600003612c92565b8d5b60008f13612cb45773fffd8963efd1fc6a506488495d951d5263988d25612cbb565b6401000276a45b3060405160200180826001600160a01b031681526020019150506040516020818303038152906040526040518663ffffffff1660e01b815260040180866001600160a01b031681526020018515158152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612d5c578181015183820152602001612d44565b50505050905090810190601f168015612d895780820380516001836020036101000a031916815260200191505b5096505050505050506040805180830381600087803b158015612dab57600080fd5b505af1158015612dbf573d6000803e3d6000fd5b505050506040513d6040811015612dd557600080fd5b50505b8d600960146101000a81548162ffffff021916908360020b62ffffff1602179055508c600960176101000a81548162ffffff021916908360020b62ffffff160217905550612f6f600960149054906101000a900460020b600960179054906101000a900460020b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612eac57600080fd5b505afa158015612ec0573d6000803e3d6000fd5b505050506040513d6020811015612ed657600080fd5b5051604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015612f3e57600080fd5b505afa158015612f52573d6000803e3d6000fd5b505050506040513d6020811015612f6857600080fd5b505161498e565b600954909850612f9590600160a01b8104600290810b91600160b81b9004900b8a614bbe565b50508b6009601a6101000a81548162ffffff021916908360020b62ffffff1602179055508a6009601d6101000a81548162ffffff021916908360020b62ffffff16021790555061306b6009601a9054906101000a900460020b6009601d9054906101000a900460020b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612eac57600080fd5b60095490975061309190600160d01b8104600290810b91600160e81b9004900b89614bbe565b505060016006555050505050505050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561315257600080fd5b505afa158015613166573d6000803e3d6000fd5b505050506040513d60e081101561317c57600080fd5b506040015161ffff16919050565b613192613697565b6001600160a01b03166131a361171a565b6001600160a01b0316146131ec576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b6001600160a01b0381166132315760405162461bcd60e51b81526004018080602001828103825260268152602001806150736026913960400191505060405180910390fd5b6007546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600780546001600160a01b0319166001600160a01b0392909216919091179055565b600e5463ffffffff1681565b6132a1613697565b6001600160a01b03166132b261171a565b6001600160a01b0316146132fb576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b60008163ffffffff1611613356576040805162461bcd60e51b815260206004820181905260248201527f49562e73657454776170506572696f643a206d697373696e6720706572696f64604482015290519081900360640190fd5b600e805463ffffffff191663ffffffff831690811790915560408051338152602081019290925280517fe4c60f4984caeb7f45b0cfe6d4233c115601ab11d141bc2cbf68b48346cdef389281900390910190a150565b600954600160a01b900460020b81565b6000808211613412576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161341b57fe5b049392505050565b60008061343085856139d9565b5050905061345a613455613442610e67565b610af86001600160801b03851687613491565b614d30565b95945050505050565b6000806001600160801b038516156134875761348287878787876142d2565b915091505b9550959350505050565b6000826134a057506000610e09565b828202828482816134ad57fe5b0414610eee5760405162461bcd60e51b815260040180806020018281038252602181526020018061514c6021913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261353c908490614d7e565b505050565b600082820183811015610eee576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6001600160a01b0382166135e05760405162461bcd60e51b81526004018080602001828103825260218152602001806151b56021913960400191505060405180910390fd5b6135ec8260008361353c565b61362981604051806060016040528060228152602001615051602291396001600160a01b03851660009081526020819052604090205491906138e2565b6001600160a01b03831660009081526020819052604090205560025461364f9082613d9d565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b3390565b6001600160a01b0383166136e05760405162461bcd60e51b81526004018080602001828103825260248152602001806151fb6024913960400191505060405180910390fd5b6001600160a01b0382166137255760405162461bcd60e51b81526004018080602001828103825260228152602001806150996022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166137cc5760405162461bcd60e51b81526004018080602001828103825260258152602001806151d66025913960400191505060405180910390fd5b6001600160a01b0382166138115760405162461bcd60e51b815260040180806020018281038252602381526020018061500e6023913960400191505060405180910390fd5b61381c83838361353c565b613859816040518060600160405280602681526020016150de602691396001600160a01b03861660009081526020819052604090205491906138e2565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546138889082613541565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156139715760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561393657818101518382015260200161391e565b50505050905090810190601f1680156139635780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526139d3908590614d7e565b50505050565b600080600080600030905062ffffff861662ffffff88168260181b1760181b1791507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663514ea4bf836040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b158015613a5f57600080fd5b505afa158015613a73573d6000803e3d6000fd5b505050506040513d60c0811015613a8957600080fd5b508051608082015160a09092015190999198509650945050505050565b600073a7e0fb32618818cfcaba025a3af3544c17ca84f66343c57a278473a7e0fb32618818cfcaba025a3af3544c17ca84f663809fdd33866040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613b1257600080fd5b505af4158015613b26573d6000803e3d6000fd5b505050506040513d6020811015613b3c57600080fd5b5051604080516001600160e01b031960e086901b16815260029390930b60048401526001600160801b0390911660248301526001600160a01b03808a16604484015288166064830152516084808301926020929190829003018186803b158015613ba557600080fd5b505af4158015613bb9573d6000803e3d6000fd5b505050506040513d6020811015613bcf57600080fd5b505195945050505050565b60008073a7e0fb32618818cfcaba025a3af3544c17ca84f6638241348988866040518363ffffffff1660e01b815260040180836001600160a01b031681526020018263ffffffff1681526020019250505060206040518083038186803b158015613c4357600080fd5b505af4158015613c57573d6000803e3d6000fd5b505050506040513d6020811015613c6d57600080fd5b50516040805163809fdd3360e01b815260048101869052905160029290920b925073a7e0fb32618818cfcaba025a3af3544c17ca84f6916343c57a27918491849163809fdd33916024808301926020929190829003018186803b158015613cd357600080fd5b505af4158015613ce7573d6000803e3d6000fd5b505050506040513d6020811015613cfd57600080fd5b5051604080516001600160e01b031960e086901b16815260029390930b60048401526001600160801b0390911660248301526001600160a01b03808b16604484015289166064830152516084808301926020929190829003018186803b158015613d6657600080fd5b505af4158015613d7a573d6000803e3d6000fd5b505050506040513d6020811015613d9057600080fd5b5051979650505050505050565b600082821115613df4576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015613e5657600080fd5b505afa158015613e6a573d6000803e3d6000fd5b505050506040513d60e0811015613e8057600080fd5b5060600151604080516314823efd60e11b815290519192506000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916329047dfa916004808301926020929190829003018186803b158015613eeb57600080fd5b505afa158015613eff573d6000803e3d6000fd5b505050506040513d6020811015613f1557600080fd5b505160408051633a76757360e11b815261ffff8516600482015290519192506000916001600160a01b038416916374eceae69160248083019260e0929190829003018186803b158015613f6757600080fd5b505afa158015613f7b573d6000803e3d6000fd5b505050506040513d60e0811015613f9157600080fd5b506020015163ffffffff16421415949350505050565b6001600160a01b038216614002576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61400e6000838361353c565b60025461401b9082613541565b6002556001600160a01b0382166000908152602081905260409020546140419082613541565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156140f557600080fd5b505afa158015614109573d6000803e3d6000fd5b505050506040513d60e081101561411f57600080fd5b50516040805163986cfba360e01b8152600289900b6004820152905191925073a7e0fb32618818cfcaba025a3af3544c17ca84f69163c72e160b918491849163986cfba3916024808301926020929190829003018186803b15801561418357600080fd5b505af4158015614197573d6000803e3d6000fd5b505050506040513d60208110156141ad57600080fd5b50516040805163986cfba360e01b815260028b900b6004820152905173a7e0fb32618818cfcaba025a3af3544c17ca84f69163986cfba3916024808301926020929190829003018186803b15801561420457600080fd5b505af4158015614218573d6000803e3d6000fd5b505050506040513d602081101561422e57600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529284166024840152921660448201526001600160801b0388166064820152815160848083019392829003018186803b15801561429057600080fd5b505af41580156142a4573d6000803e3d6000fd5b505050506040513d60408110156142ba57600080fd5b5080516020909101519093509150505b935093915050565b6040805163a34123a760e01b8152600287810b600483015286900b60248201526001600160801b038516604482015281516000928392839283926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a34123a7926064808301939282900301818787803b15801561435957600080fd5b505af115801561436d573d6000803e3d6000fd5b505050506040513d604081101561438357600080fd5b50805160209091015190925090506000856143a6576143a183614d30565b6143af565b6001600160801b035b90506000866143c6576143c183614d30565b6143cf565b6001600160801b035b90506000826001600160801b031611806143f257506000816001600160801b0316115b156144cc57604080516309e3d67b60e31b81526001600160a01b038a8116600483015260028e810b60248401528d900b60448301526001600160801b0385811660648401528416608483015282517f000000000000000000000000000000000000000000000000000000000000000090911692634f1eb3d89260a480820193918290030181600087803b15801561448857600080fd5b505af115801561449c573d6000803e3d6000fd5b505050506040513d60408110156144b257600080fd5b5080516020909101516001600160801b0391821697501694505b505050509550959350505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663665a17c56040518163ffffffff1660e01b815260040160206040518083038186803b15801561453557600080fd5b505afa158015614549573d6000803e3d6000fd5b505050506040513d602081101561455f57600080fd5b5051604080516337792e1d60e11b815290519192506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691636ef25c3a916004808301926020929190829003018186803b1580156145c757600080fd5b505afa1580156145db573d6000803e3d6000fd5b505050506040513d60208110156145f157600080fd5b50519050811580159061460e57506008546001600160a01b031615155b156146cd57831561467057600854614670906001600160a01b031661463f670de0b6b3a7640000610af88887613491565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906134ea565b82156146cd576008546146cd906001600160a01b031661469c670de0b6b3a7640000610af88787613491565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906134ea565b80156139d3576009546000906001600160a01b031615614771577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663acc8247d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561474057600080fd5b505afa158015614754573d6000803e3d6000fd5b505050506040513d602081101561476a57600080fd5b505161477b565b670de0b6b3a76400005b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663469048406040518163ffffffff1660e01b815260040160206040518083038186803b1580156147d857600080fd5b505afa1580156147ec573d6000803e3d6000fd5b505050506040513d602081101561480257600080fd5b5051905085156148c6576000614824670de0b6b3a7640000610af88987613491565b9050600061483e670de0b6b3a7640000610af88487613491565b9050600061484c8383613d9d565b90506148826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001685846134ea565b80156148c2576009546148c2906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836134ea565b5050505b84156149865760006148e4670de0b6b3a7640000610af88887613491565b905060006148fe670de0b6b3a7640000610af88487613491565b9050600061490c8383613d9d565b90506149426001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001685846134ea565b801561498257600954614982906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836134ea565b5050505b505050505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156149ea57600080fd5b505afa1580156149fe573d6000803e3d6000fd5b505050506040513d60e0811015614a1457600080fd5b50516040805163986cfba360e01b8152600289900b6004820152905191925073a7e0fb32618818cfcaba025a3af3544c17ca84f691636098fd4a918491849163986cfba3916024808301926020929190829003018186803b158015614a7857600080fd5b505af4158015614a8c573d6000803e3d6000fd5b505050506040513d6020811015614aa257600080fd5b50516040805163986cfba360e01b815260028b900b6004820152905173a7e0fb32618818cfcaba025a3af3544c17ca84f69163986cfba3916024808301926020929190829003018186803b158015614af957600080fd5b505af4158015614b0d573d6000803e3d6000fd5b505050506040513d6020811015614b2357600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529284166024840152921660448201526064810188905260848101879052905160a4808301926020929190829003018186803b158015614b8857600080fd5b505af4158015614b9c573d6000803e3d6000fd5b505050506040513d6020811015614bb257600080fd5b50519695505050505050565b6000806001600160801b038316156142ca5760408051306020808301829052835180840382018152838501948590526302abf8a760e61b909452604483018281526064840183905260028a810b608486015289900b60a48501526001600160801b03881660c485015260c060e48501908152855161010486015285516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169663aafe29c09686958e958e958e9591939092610124909101919085019080838360005b83811015614ca0578181015183820152602001614c88565b50505050905090810190601f168015614ccd5780820380516001836020036101000a031916815260200191505b50975050505050505050606060405180830381600087803b158015614cf157600080fd5b505af1158015614d05573d6000803e3d6000fd5b505050506040513d6060811015614d1b57600080fd5b50805160209091015190969095509350505050565b60006001600160801b03821115614d7a576040805162461bcd60e51b815260206004820152600960248201526824ab1718991c2fa7a360b91b604482015290519081900360640190fd5b5090565b6000614dd3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e2f9092919063ffffffff16565b80519091501561353c57808060200190516020811015614df257600080fd5b505161353c5760405162461bcd60e51b815260040180806020018281038252602a815260200180615240602a913960400191505060405180910390fd5b6060614e3e8484600085614e46565b949350505050565b606082471015614e875760405162461bcd60e51b81526004018080602001828103825260268152602001806151046026913960400191505060405180910390fd5b614e9085614fa1565b614ee1576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310614f1f5780518252601f199092019160209182019101614f00565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614f81576040519150601f19603f3d011682016040523d82523d6000602084013e614f86565b606091505b5091509150614f96828286614fa7565b979650505050505050565b3b151590565b60608315614fb6575081610eee565b825115614fc65782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561393657818101518382015260200161391e56fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573735265656e7472616e637947756172643a207265656e7472616e742063616c6c0045524332303a206275726e20616d6f756e7420657863656564732062616c616e63654f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737349562e726562616c616e63653a206261736520706f736974696f6e20696e76616c696445524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c49562e63757272656e745469636b3a2074686520706f6f6c206973206c6f636b6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657245524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737349562e726562616c616e63653a206964656e746963616c20706f736974696f6e735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656449562e726562616c616e63653a206c696d697420706f736974696f6e20696e76616c696445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220e2aa6d6d66579ffe132dfe562d7a7dea7ac9f2381ec76dca97937b5a075b3bc764736f6c634300070600334f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573738be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e049562e636f6e7374727563746f723a206e6f20616c6c6f77656420746f6b656e73a2646970667358221220f001da2d4bda9e8609058e5568a6e50abd1625193dec8134e78e1a534ffe675c64736f6c63430007060033
Deployed Bytecode
0x73e2381b5afae99b899596bc550184a080daa31f2630146080604052600436106100355760003560e01c8063ade6c30a1461003a575b600080fd5b81801561004657600080fd5b506100a1600480360360e081101561005d57600080fd5b506001600160a01b03813581169160208101358216916040820135151591606081013590911690608081013515159063ffffffff60a0820135169060c001356100bd565b604080516001600160a01b039092168252519081900360200190f35b6000338787878760405160200180866001600160a01b031660601b8152601401856001600160a01b031660601b815260140184151560f81b8152600101836001600160a01b031660601b815260140182151560f81b81526001019550505050505060405160208183030381529060405280519060200120888786338787604051610146906101b1565b6001600160a01b039687168152941515602086015292151560408086019190915291909416606084015263ffffffff909316608083015260a08201529051829181900360c001906000f59050801580156101a4573d6000803e3d6000fd5b5098975050505050505050565b615c09806101bf8339019056fe6101406040523480156200001257600080fd5b5060405162005c0938038062005c09833981810160405260c08110156200003857600080fd5b5080516020808301516040808501516060860151608087015160a09097015183518085018552601481527f49434849205661756c74204c6971756964697479000000000000000000000000968101969096528351639c6dde5360e01b8152600481018290529351969794969295919493909273a7e0fb32618818cfcaba025a3af3544c17ca84f691639c6dde53916024808301926000929190829003018186803b158015620000e657600080fd5b505af4158015620000fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156200012557600080fd5b81019080805160405193929190846401000000008211156200014657600080fd5b9083019060208201858111156200015c57600080fd5b82516401000000008111828201881017156200017757600080fd5b82525081516020918201929091019080838360005b83811015620001a65781810151838201526020016200018c565b50505050905090810190601f168015620001d45780820380516001836020036101000a031916815260200191505b5060405250508251620001f09150600390602085019062000695565b5080516200020690600490602084019062000695565b50506005805460ff191660121790555060016006556000620002276200050e565b600780546001600160a01b0319166001600160a01b0383169081179091556040519192509060009060008051602062005bc8833981519152908290a3506001600160a01b038616620002c0576040805162461bcd60e51b815260206004820152601c60248201527f49562e636f6e7374727563746f723a207a65726f206164647265737300000000604482015290519081900360640190fd5b8480620002ca5750835b620003075760405162461bcd60e51b815260040180806020018281038252602181526020018062005be86021913960400191505060405180910390fd5b33606090811b60805286901b6001600160601b03191660a05260408051630dfe168160e01b815290516001600160a01b03881691630dfe1681916004808301926020929190829003018186803b1580156200036157600080fd5b505afa15801562000376573d6000803e3d6000fd5b505050506040513d60208110156200038d57600080fd5b505160601b6001600160601b03191660c0526040805163d21220a760e01b815290516001600160a01b0388169163d21220a7916004808301926020929190829003018186803b158015620003e057600080fd5b505afa158015620003f5573d6000803e3d6000fd5b505050506040513d60208110156200040c57600080fd5b505160601b6001600160601b03191660e05284151560f890811b61010052841515901b61012052600e805463ffffffff191663ffffffff8416179055620004538362000512565b6000600c5562000479670de0b6b3a764000060646200061d602090811b620033bc17901c565b600d55600019600a819055600b55600880546001600160a01b031990811690915560098054909116905560408051861515815285151560208201526001600160a01b038581168284015263ffffffff8516606083015291519188169133917f3e708ccf7d0e6de8558e020ea36189511cb3435bbfec54e721a48ee4df0d4f8c919081900360800190a350505050505062000741565b3390565b6200051c6200050e565b6001600160a01b03166200052f62000686565b6001600160a01b0316146200058b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116620005d25760405162461bcd60e51b815260040180806020018281038252602681526020018062005ba26026913960400191505060405180910390fd5b6007546040516001600160a01b0380841692169060008051602062005bc883398151915290600090a3600780546001600160a01b0319166001600160a01b0392909216919091179055565b600080821162000674576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816200067e57fe5b049392505050565b6007546001600160a01b031690565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282620006cd576000855562000718565b82601f10620006e857805160ff191683800117855562000718565b8280016001018555821562000718579182015b8281111562000718578251825591602001919060010190620006fb565b50620007269291506200072a565b5090565b5b808211156200072657600081556001016200072b565b60805160601c60a05160601c60c05160601c60e05160601c6101005160f81c6101205160f81c6152e8620008ba6000398061115852806117f35250806116205280611778525080610b0c5280610bc652806110ea528061111e528061129f52806113145280611c825280611d0a5280611e6b528061222452806124e05280612b955280612ef852806146a6528061491b5280614959525080610a5b5280610b8c5280610e11528061105d5280611096528061126552806112d95280611c615280611ce85280611e30528061217b5280612b035280612e4152806130005280614649528061485b5280614899525080610c875280610e455280610fbf52806111d35280611a1a5280611b7e5280611cc65280612456528061260f5280612867528061295e5280612c5852806130fb52806139fd5280613dff5280613ea5528061409e5280614316528061444252806149935280614c445250806130d552806144de528061458152806146e9528061478152506152e86000f3fe608060405234801561001057600080fd5b50600436106102d55760003560e01c80637aea530911610182578063c4a7761e116100e9578063dd62ed3e116100a2578063f2fde38b1161007c578063f2fde38b1461087b578063f6207326146108a1578063f9c95d46146108c2578063fa082743146108e5576102d5565b8063dd62ed3e14610825578063dd81fa6314610853578063ddca3f431461085b576102d5565b8063c4a7761e146107bc578063c8796572146107c4578063d0c93a7c146107cc578063d21220a7146107d4578063d2eabcfc146107dc578063d87346aa146107e4576102d5565b80638dbdbe6d1161013b5780638dbdbe6d146106f257806395d89b4114610724578063a049de6b1461072c578063a457c2d71461075c578063a9059cbb14610788578063aaf5eb68146107b4576102d5565b80637aea5309146106a45780637f7a1eec146106ac57806381de128b146106b4578063888a9134146106da578063897f078c146106e25780638da5cb5b146106ea576102d5565b8063313ce5671161024157806345e05f43116101fa5780635ffc1ff7116101d45780635ffc1ff714610651578063648cab851461066e57806370a0823114610676578063715018a61461069c576102d5565b806345e05f43146106395780634d461fbb1461064157806351e87af714610649576102d5565b8063313ce5671461052b57806337e41b401461054957806339509351146105515780633dd657c51461057d5780633e091ee9146105f95780633f3e4c111461061c576102d5565b806316f0115b1161029357806316f0115b1461042757806318160ddd1461042f57806323b872dd146104495780632ab4d0521461047f5780632bbb56d9146104875780632c8958f6146104af576102d5565b8062f714ce146102da578063065e53601461031f57806306fdde031461033e578063095ea7b3146103bb5780630dfe1681146103fb5780630f35bcac1461041f575b600080fd5b610306600480360360408110156102f057600080fd5b50803590602001356001600160a01b03166108ed565b6040805192835260208301919091528051918290030190f35b610327610c80565b6040805160029290920b8252519081900360200190f35b610346610d5b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610380578181015183820152602001610368565b50505050905090810190601f1680156103ad5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103e7600480360360408110156103d157600080fd5b506001600160a01b038135169060200135610df1565b604080519115158252519081900360200190f35b610403610e0f565b604080516001600160a01b039092168252519081900360200190f35b610327610e33565b610403610e43565b610437610e67565b60408051918252519081900360200190f35b6103e76004803603606081101561045f57600080fd5b506001600160a01b03813581169160208101359091169060400135610e6d565b610437610ef5565b6104ad6004803603602081101561049d57600080fd5b50356001600160a01b0316610efb565b005b6104ad600480360360608110156104c557600080fd5b8135916020810135918101906060810160408201356401000000008111156104ec57600080fd5b8201836020820111156104fe57600080fd5b8035906020019184600183028401116401000000008311171561052057600080fd5b509092509050610fb4565b61053361114d565b6040805160ff9092168252519081900360200190f35b6103e7611156565b6103e76004803603604081101561056757600080fd5b506001600160a01b03813516906020013561117a565b6104ad6004803603606081101561059357600080fd5b8135916020810135918101906060810160408201356401000000008111156105ba57600080fd5b8201836020820111156105cc57600080fd5b803590602001918460018302840111640100000000831117156105ee57600080fd5b5090925090506111c8565b6104ad6004803603604081101561060f57600080fd5b508035906020013561133c565b6104ad6004803603602081101561063257600080fd5b50356113e6565b610403611486565b610437611495565b61032761149b565b6104ad6004803603602081101561066757600080fd5b50356114ab565b61043761154b565b6104376004803603602081101561068c57600080fd5b50356001600160a01b0316611551565b6104ad61156c565b610437611618565b6103e761161e565b6104ad600480360360208110156106ca57600080fd5b50356001600160a01b0316611642565b6103276116fb565b61040361170b565b61040361171a565b6104376004803603606081101561070857600080fd5b50803590602081013590604001356001600160a01b0316611729565b610346611fcd565b61073461202e565b604080516001600160801b039094168452602084019290925282820152519081900360600190f35b6103e76004803603604081101561077257600080fd5b506001600160a01b0381351690602001356120c6565b6103e76004803603604081101561079e57600080fd5b506001600160a01b03813516906020013561212e565b610437612142565b61030661214e565b610306612299565b610327612452565b6104036124de565b610734612502565b6104ad600480360360a08110156107fa57600080fd5b508035600290810b916020810135820b916040820135810b91606081013590910b906080013561255e565b6104376004803603604081101561083b57600080fd5b506001600160a01b03813581169160200135166130a8565b6104036130d3565b6108636130f7565b6040805162ffffff9092168252519081900360200190f35b6104ad6004803603602081101561089157600080fd5b50356001600160a01b031661318a565b6108a961328d565b6040805163ffffffff9092168252519081900360200190f35b6104ad600480360360208110156108d857600080fd5b503563ffffffff16613299565b6103276133ac565b60008060026006541415610936576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b600260065583610983576040805162461bcd60e51b815260206004820152601360248201527249562e77697468647261773a2073686172657360681b604482015290519081900360640190fd5b6001600160a01b0383166109d0576040805162461bcd60e51b815260206004820152600f60248201526e49562e77697468647261773a20746f60881b604482015290519081900360640190fd5b6009546000908190610a0590600160a01b8104600290810b91600160b81b9004900b6109fd82828b613423565b886000613463565b60095491935091506000908190610a3f90600160d01b8104600290810b91600160e81b9004900b610a3782828d613423565b8a6000613463565b915091506000610a4d610e67565b90506000610afe82610af88c7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610ac657600080fd5b505afa158015610ada573d6000803e3d6000fd5b505050506040513d6020811015610af057600080fd5b505190613491565b906133bc565b90506000610b7783610af88d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015610ac657600080fd5b90508115610bb357610bb36001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b846134ea565b8015610bed57610bed6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168b836134ea565b610c0182610bfb8988613541565b90613541565b9850610c1181610bfb8887613541565b9750610c1d338c61359b565b604080518c8152602081018b90528082018a905290516001600160a01b038c169133917febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f9181900360600190a35050505050505060016006819055509250929050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015610cde57600080fd5b505afa158015610cf2573d6000803e3d6000fd5b505050506040513d60e0811015610d0857600080fd5b50602081015160c090910151909250905080610d555760405162461bcd60e51b815260040180806020018281038252602281526020018061512a6022913960400191505060405180910390fd5b50919050565b60038054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610de75780601f10610dbc57610100808354040283529160200191610de7565b820191906000526020600020905b815481529060010190602001808311610dca57829003601f168201915b5050505050905090565b6000610e05610dfe613697565b848461369b565b5060015b92915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600954600160e81b900460020b81565b7f000000000000000000000000000000000000000000000000000000000000000081565b60025490565b6000610e7a848484613787565b610eea84610e86613697565b610ee58560405180606001604052806028815260200161516d602891396001600160a01b038a16600090815260016020526040812090610ec4613697565b6001600160a01b0316815260208101919091526040016000205491906138e2565b61369b565b5060015b9392505050565b600c5481565b610f03613697565b6001600160a01b0316610f1461171a565b6001600160a01b031614610f5d576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600980546001600160a01b0383166001600160a01b03199091168117909155604080519182525133917f3066ef5dd340e8b2ea28d62f5a8391eb7a82d3ee87532724a1ca4386d34f7523919081900360200190a250565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611017576040805162461bcd60e51b815260206004820152600360248201526231b11960e91b604482015290519081900360640190fd5b60008282602081101561102957600080fd5b50356001600160a01b0316905060008513156110c3576001600160a01b038116301415611089576110846001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633876134ea565b6110be565b6110be6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823388613979565b611146565b6000841315611146576001600160a01b038116301415611111576110be6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633866134ea565b6111466001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823387613979565b5050505050565b60055460ff1690565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610e05611187613697565b84610ee58560016000611198613697565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490613541565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461122b576040805162461bcd60e51b815260206004820152600360248201526263623160e81b604482015290519081900360640190fd5b60008282602081101561123d57600080fd5b50356001600160a01b03169050308114156112c657841561128c5761128c6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633876134ea565b83156110be576110be6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633866134ea565b8415611301576113016001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823388613979565b8315611146576111466001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823387613979565b611344613697565b6001600160a01b031661135561171a565b6001600160a01b03161461139e576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600a829055600b8190556040805183815260208101839052815133927fafd3b05a4086b378b6f291200a528d8aed8c5e0317af77436b001f1bec28821a928290030190a25050565b6113ee613697565b6001600160a01b03166113ff61171a565b6001600160a01b031614611448576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600c81905560408051828152905133917f7423cea36ad2104e8e8c3d9aa1e24288bdf3bfa7b4f37868cfa6d4d34ffdaf3a919081900360200190a250565b6009546001600160a01b031681565b600b5481565b600954600160d01b900460020b81565b6114b3613697565b6001600160a01b03166114c461171a565b6001600160a01b03161461150d576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600d81905560408051828152905133917f529698f34660760dcb172def5c99d62e1b5b74b444df322e8f7da31f2bd0a86b919081900360200190a250565b600a5481565b6001600160a01b031660009081526020819052604090205490565b611574613697565b6001600160a01b031661158561171a565b6001600160a01b0316146115ce576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b6007546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600780546001600160a01b0319169055565b600d5481565b7f000000000000000000000000000000000000000000000000000000000000000081565b61164a613697565b6001600160a01b031661165b61171a565b6001600160a01b0316146116a4576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b600880546001600160a01b0383166001600160a01b03199091168117909155604080519182525133917fbb78b7c13893a913fa8c9ecb9fdaf97597aa412a39c778bf976790555f0942f7919081900360200190a250565b600954600160b81b900460020b81565b6008546001600160a01b031681565b6007546001600160a01b031690565b600060026006541415611771576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b60026006557f0000000000000000000000000000000000000000000000000000000000000000806117a0575083155b6117f1576040805162461bcd60e51b815260206004820152601e60248201527f49562e6465706f7369743a20746f6b656e30206e6f7420616c6c6f7765640000604482015290519081900360640190fd5b7f00000000000000000000000000000000000000000000000000000000000000008061181b575082155b61186c576040805162461bcd60e51b815260206004820152601e60248201527f49562e6465706f7369743a20746f6b656e31206e6f7420616c6c6f7765640000604482015290519081900360640190fd5b600084118061187b5750600083115b6118cc576040805162461bcd60e51b815260206004820181905260248201527f49562e6465706f7369743a206465706f73697473206d757374206265203e2030604482015290519081900360640190fd5b600a54841080156118de5750600b5483105b61192f576040805162461bcd60e51b815260206004820152601e60248201527f49562e6465706f7369743a206465706f7369747320746f6f206c617267650000604482015290519081900360640190fd5b6001600160a01b0382161580159061195057506001600160a01b0382163014155b611992576040805162461bcd60e51b815260206004820152600e60248201526d49562e6465706f7369743a20746f60901b604482015290519081900360640190fd5b6009546000906119b790600160a01b8104600290810b91600160b81b9004900b6139d9565b50909150506001600160801b03811615611af6576009546040805163a34123a760e01b8152600160a01b8304600290810b810b6004830152600160b81b909304830b90920b60248301526000604483018190528151909283926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a34123a792606480820193929182900301818787803b158015611a5e57600080fd5b505af1158015611a72573d6000803e3d6000fd5b505050506040513d6040811015611a8857600080fd5b508051602090910151909250905081158015611aa2575080155b611af3576040805162461bcd60e51b815260206004820152601f60248201527f49562e6465706f7369743a20756e6578706563746564206275726e2028312900604482015290519081900360640190fd5b50505b600954600090611b1b90600160d01b8104600290810b91600160e81b9004900b6139d9565b50909150506001600160801b03811615611c5a576009546040805163a34123a760e01b8152600160d01b8304600290810b810b6004830152600160e81b909304830b90920b60248301526000604483018190528151909283926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a34123a792606480820193929182900301818787803b158015611bc257600080fd5b505af1158015611bd6573d6000803e3d6000fd5b505050506040513d6040811015611bec57600080fd5b508051602090910151909250905081158015611c06575080155b611c57576040805162461bcd60e51b815260206004820152601f60248201527f49562e6465706f7369743a20756e6578706563746564206275726e2028322900604482015290519081900360640190fd5b50505b6000611cb77f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000611ca9610c80565b670de0b6b3a7640000613aa6565b600e54909150600090611d3e907f0000000000000000000000000000000000000000000000000000000000000000907f0000000000000000000000000000000000000000000000000000000000000000907f00000000000000000000000000000000000000000000000000000000000000009063ffffffff16670de0b6b3a7640000613bda565b90506000818311611d6e57611d6982610af8670de0b6b3a7640000611d638388613d9d565b90613491565b611d88565b611d8883610af8670de0b6b3a7640000611d638387613d9d565b9050600d54811115611de557611d9c613dfa565b611de5576040805162461bcd60e51b815260206004820152601560248201527424ab173232b837b9b4ba1d103a393c903630ba32b960591b604482015290519081900360640190fd5b600080611df061214e565b915091506000611e1b670de0b6b3a7640000610af8878910611e125787611e14565b885b8f90613491565b90508b15611e5857611e586001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308f613979565b8a15611e9357611e936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633308e613979565b611e9d8b82613541565b9850611ea7610e67565b15611ef8576000611ed3670de0b6b3a7640000610af8888a11611eca5788611ecc565b895b8790613491565b9050611ef4611ee28285613541565b610af8611eed610e67565b8d90613491565b9950505b611f028a8a613fa7565b604080518a8152602081018e90528082018d905290516001600160a01b038c169133917f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f69181900360600190a3600c541580611f675750600c54611f64610e67565b11155b611fb8576040805162461bcd60e51b815260206004820152601a60248201527f49562e6465706f7369743a206d6178546f74616c537570706c79000000000000604482015290519081900360640190fd5b50506001600655509498975050505050505050565b60048054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610de75780601f10610dbc57610100808354040283529160200191610de7565b60008060008060008061205f6009601a9054906101000a900460020b6009601d9054906101000a900460020b6139d9565b600954929550909350915061208a90600160d01b8104600290810b91600160e81b9004900b85614097565b939650945091925084916120a7856001600160801b038416613541565b94506120bc846001600160801b038316613541565b9350505050909192565b6000610e056120d3613697565b84610ee58560405180606001604052806025815260200161528e60259139600160006120fd613697565b6001600160a01b03908116825260208083019390935260409182016000908120918d168152925290205491906138e2565b6000610e0561213b613697565b8484613787565b670de0b6b3a764000081565b60008060008061215c612502565b925092505060008061216c61202e565b925092505061221882610bfb867f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156121e657600080fd5b505afa1580156121fa573d6000803e3d6000fd5b505050506040513d602081101561221057600080fd5b505190613541565b955061228f81610bfb857f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156121e657600080fd5b9450505050509091565b600080600260065414156122e2576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b6002600681905560095460009161230c91600160a01b8104820b91600160b81b909104900b6139d9565b50909150506001600160801b0381161561236b57600954600090819061234b90600160a01b8104600290810b91600160b81b9004900b833060016142d2565b909250905061235a8583613541565b94506123668482613541565b935050505b60095460009061239090600160d01b8104600290810b91600160e81b9004900b6139d9565b50909150506001600160801b038116156123ef5760095460009081906123cf90600160d01b8104600290810b91600160e81b9004900b833060016142d2565b90925090506123de8683613541565b95506123ea8582613541565b945050505b6040805185815260208101859052815133927fec8208dd791fa8ffdc0d7427f3ba9c0ed06f1bce9a86254e6940c10cc1802fef928290030190a260008411806124385750600083115b156124475761244784846144da565b505060016006559091565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0c93a7c6040518163ffffffff1660e01b815260040160206040518083038186803b1580156124ad57600080fd5b505afa1580156124c1573d6000803e3d6000fd5b505050506040513d60208110156124d757600080fd5b5051905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b600080600080600080612533600960149054906101000a900460020b600960179054906101000a900460020b6139d9565b600954929550909350915061208a90600160a01b8104600290810b91600160b81b9004900b85614097565b600260065414156125a4576040805162461bcd60e51b815260206004820152601f6024820152600080516020615031833981519152604482015290519081900360640190fd5b60026006556125b1613697565b6001600160a01b03166125c261171a565b6001600160a01b03161461260b576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0c93a7c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561266657600080fd5b505afa15801561267a573d6000803e3d6000fd5b505050506040513d602081101561269057600080fd5b50519050600285810b9087900b1280156126ba57508060020b8660020b816126b457fe5b0760020b155b80156126d657508060020b8560020b816126d057fe5b0760020b155b6127115760405162461bcd60e51b81526004018080602001828103825260238152602001806150bb6023913960400191505060405180910390fd5b8260020b8460020b12801561273657508060020b8460020b8161273057fe5b0760020b155b801561275257508060020b8360020b8161274c57fe5b0760020b155b61278d5760405162461bcd60e51b815260040180806020018281038252602481526020018061526a6024913960400191505060405180910390fd5b8360020b8660020b1415806127a857508260020b8560020b14155b6127e35760405162461bcd60e51b815260040180806020018281038252602181526020018061521f6021913960400191505060405180910390fd5b60095460009061280890600160a01b8104600290810b91600160b81b9004900b6139d9565b50909150506001600160801b038116156128da576009546040805163a34123a760e01b8152600160a01b8304600290810b810b6004830152600160b81b909304830b90920b602483015260006044830181905281516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363a34123a7936064808301949193928390030190829087803b1580156128ad57600080fd5b505af11580156128c1573d6000803e3d6000fd5b505050506040513d60408110156128d757600080fd5b50505b6009546000906128ff90600160d01b8104600290810b91600160e81b9004900b6139d9565b50909150506001600160801b038116156129d1576009546040805163a34123a760e01b8152600160d01b8304600290810b810b6004830152600160e81b909304830b90920b602483015260006044830181905281516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169363a34123a7936064808301949193928390030190829087803b1580156129a457600080fd5b505af11580156129b8573d6000803e3d6000fd5b505050506040513d60408110156129ce57600080fd5b50505b60095460009081906129f890600160a01b8104600290810b91600160b81b9004900b6139d9565b6009546001600160801b03928316955091169250600091508190612a3190600160d01b8104600290810b91600160e81b9004900b6139d9565b6001600160801b03918216945016915060009050612a4f8584613541565b90506000612a5d8584613541565b600954909150612a8690600160a01b8104600290810b91600160b81b9004900b8a306001613463565b5050600954612aae90600160d01b8104600290810b91600160e81b9004900b89306001613463565b5050612aba82826144da565b7fbc4c20ad04f161d631d9ce94d27659391196415aa3c42f6a71c62e905ece782d612ae3610c80565b604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015612b4957600080fd5b505afa158015612b5d573d6000803e3d6000fd5b505050506040513d6020811015612b7357600080fd5b5051604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015612bdb57600080fd5b505afa158015612bef573d6000803e3d6000fd5b505050506040513d6020811015612c0557600080fd5b50518585612c11610e67565b6040805160029790970b87526020870195909552858501939093526060850191909152608084015260a0830152519081900360c00190a18915612dd8576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663128acb083060008d1380612c90578d600003612c92565b8d5b60008f13612cb45773fffd8963efd1fc6a506488495d951d5263988d25612cbb565b6401000276a45b3060405160200180826001600160a01b031681526020019150506040516020818303038152906040526040518663ffffffff1660e01b815260040180866001600160a01b031681526020018515158152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015612d5c578181015183820152602001612d44565b50505050905090810190601f168015612d895780820380516001836020036101000a031916815260200191505b5096505050505050506040805180830381600087803b158015612dab57600080fd5b505af1158015612dbf573d6000803e3d6000fd5b505050506040513d6040811015612dd557600080fd5b50505b8d600960146101000a81548162ffffff021916908360020b62ffffff1602179055508c600960176101000a81548162ffffff021916908360020b62ffffff160217905550612f6f600960149054906101000a900460020b600960179054906101000a900460020b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612eac57600080fd5b505afa158015612ec0573d6000803e3d6000fd5b505050506040513d6020811015612ed657600080fd5b5051604080516370a0823160e01b815230600482015290516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916370a08231916024808301926020929190829003018186803b158015612f3e57600080fd5b505afa158015612f52573d6000803e3d6000fd5b505050506040513d6020811015612f6857600080fd5b505161498e565b600954909850612f9590600160a01b8104600290810b91600160b81b9004900b8a614bbe565b50508b6009601a6101000a81548162ffffff021916908360020b62ffffff1602179055508a6009601d6101000a81548162ffffff021916908360020b62ffffff16021790555061306b6009601a9054906101000a900460020b6009601d9054906101000a900460020b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b158015612eac57600080fd5b60095490975061309190600160d01b8104600290810b91600160e81b9004900b89614bbe565b505060016006555050505050505050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561315257600080fd5b505afa158015613166573d6000803e3d6000fd5b505050506040513d60e081101561317c57600080fd5b506040015161ffff16919050565b613192613697565b6001600160a01b03166131a361171a565b6001600160a01b0316146131ec576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b6001600160a01b0381166132315760405162461bcd60e51b81526004018080602001828103825260268152602001806150736026913960400191505060405180910390fd5b6007546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600780546001600160a01b0319166001600160a01b0392909216919091179055565b600e5463ffffffff1681565b6132a1613697565b6001600160a01b03166132b261171a565b6001600160a01b0316146132fb576040805162461bcd60e51b81526020600482018190526024820152600080516020615195833981519152604482015290519081900360640190fd5b60008163ffffffff1611613356576040805162461bcd60e51b815260206004820181905260248201527f49562e73657454776170506572696f643a206d697373696e6720706572696f64604482015290519081900360640190fd5b600e805463ffffffff191663ffffffff831690811790915560408051338152602081019290925280517fe4c60f4984caeb7f45b0cfe6d4233c115601ab11d141bc2cbf68b48346cdef389281900390910190a150565b600954600160a01b900460020b81565b6000808211613412576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161341b57fe5b049392505050565b60008061343085856139d9565b5050905061345a613455613442610e67565b610af86001600160801b03851687613491565b614d30565b95945050505050565b6000806001600160801b038516156134875761348287878787876142d2565b915091505b9550959350505050565b6000826134a057506000610e09565b828202828482816134ad57fe5b0414610eee5760405162461bcd60e51b815260040180806020018281038252602181526020018061514c6021913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261353c908490614d7e565b505050565b600082820183811015610eee576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6001600160a01b0382166135e05760405162461bcd60e51b81526004018080602001828103825260218152602001806151b56021913960400191505060405180910390fd5b6135ec8260008361353c565b61362981604051806060016040528060228152602001615051602291396001600160a01b03851660009081526020819052604090205491906138e2565b6001600160a01b03831660009081526020819052604090205560025461364f9082613d9d565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b3390565b6001600160a01b0383166136e05760405162461bcd60e51b81526004018080602001828103825260248152602001806151fb6024913960400191505060405180910390fd5b6001600160a01b0382166137255760405162461bcd60e51b81526004018080602001828103825260228152602001806150996022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166137cc5760405162461bcd60e51b81526004018080602001828103825260258152602001806151d66025913960400191505060405180910390fd5b6001600160a01b0382166138115760405162461bcd60e51b815260040180806020018281038252602381526020018061500e6023913960400191505060405180910390fd5b61381c83838361353c565b613859816040518060600160405280602681526020016150de602691396001600160a01b03861660009081526020819052604090205491906138e2565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546138889082613541565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156139715760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561393657818101518382015260200161391e565b50505050905090810190601f1680156139635780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b1790526139d3908590614d7e565b50505050565b600080600080600030905062ffffff861662ffffff88168260181b1760181b1791507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663514ea4bf836040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b158015613a5f57600080fd5b505afa158015613a73573d6000803e3d6000fd5b505050506040513d60c0811015613a8957600080fd5b508051608082015160a09092015190999198509650945050505050565b600073a7e0fb32618818cfcaba025a3af3544c17ca84f66343c57a278473a7e0fb32618818cfcaba025a3af3544c17ca84f663809fdd33866040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b158015613b1257600080fd5b505af4158015613b26573d6000803e3d6000fd5b505050506040513d6020811015613b3c57600080fd5b5051604080516001600160e01b031960e086901b16815260029390930b60048401526001600160801b0390911660248301526001600160a01b03808a16604484015288166064830152516084808301926020929190829003018186803b158015613ba557600080fd5b505af4158015613bb9573d6000803e3d6000fd5b505050506040513d6020811015613bcf57600080fd5b505195945050505050565b60008073a7e0fb32618818cfcaba025a3af3544c17ca84f6638241348988866040518363ffffffff1660e01b815260040180836001600160a01b031681526020018263ffffffff1681526020019250505060206040518083038186803b158015613c4357600080fd5b505af4158015613c57573d6000803e3d6000fd5b505050506040513d6020811015613c6d57600080fd5b50516040805163809fdd3360e01b815260048101869052905160029290920b925073a7e0fb32618818cfcaba025a3af3544c17ca84f6916343c57a27918491849163809fdd33916024808301926020929190829003018186803b158015613cd357600080fd5b505af4158015613ce7573d6000803e3d6000fd5b505050506040513d6020811015613cfd57600080fd5b5051604080516001600160e01b031960e086901b16815260029390930b60048401526001600160801b0390911660248301526001600160a01b03808b16604484015289166064830152516084808301926020929190829003018186803b158015613d6657600080fd5b505af4158015613d7a573d6000803e3d6000fd5b505050506040513d6020811015613d9057600080fd5b5051979650505050505050565b600082821115613df4576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015613e5657600080fd5b505afa158015613e6a573d6000803e3d6000fd5b505050506040513d60e0811015613e8057600080fd5b5060600151604080516314823efd60e11b815290519192506000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916329047dfa916004808301926020929190829003018186803b158015613eeb57600080fd5b505afa158015613eff573d6000803e3d6000fd5b505050506040513d6020811015613f1557600080fd5b505160408051633a76757360e11b815261ffff8516600482015290519192506000916001600160a01b038416916374eceae69160248083019260e0929190829003018186803b158015613f6757600080fd5b505afa158015613f7b573d6000803e3d6000fd5b505050506040513d60e0811015613f9157600080fd5b506020015163ffffffff16421415949350505050565b6001600160a01b038216614002576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61400e6000838361353c565b60025461401b9082613541565b6002556001600160a01b0382166000908152602081905260409020546140419082613541565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156140f557600080fd5b505afa158015614109573d6000803e3d6000fd5b505050506040513d60e081101561411f57600080fd5b50516040805163986cfba360e01b8152600289900b6004820152905191925073a7e0fb32618818cfcaba025a3af3544c17ca84f69163c72e160b918491849163986cfba3916024808301926020929190829003018186803b15801561418357600080fd5b505af4158015614197573d6000803e3d6000fd5b505050506040513d60208110156141ad57600080fd5b50516040805163986cfba360e01b815260028b900b6004820152905173a7e0fb32618818cfcaba025a3af3544c17ca84f69163986cfba3916024808301926020929190829003018186803b15801561420457600080fd5b505af4158015614218573d6000803e3d6000fd5b505050506040513d602081101561422e57600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529284166024840152921660448201526001600160801b0388166064820152815160848083019392829003018186803b15801561429057600080fd5b505af41580156142a4573d6000803e3d6000fd5b505050506040513d60408110156142ba57600080fd5b5080516020909101519093509150505b935093915050565b6040805163a34123a760e01b8152600287810b600483015286900b60248201526001600160801b038516604482015281516000928392839283926001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263a34123a7926064808301939282900301818787803b15801561435957600080fd5b505af115801561436d573d6000803e3d6000fd5b505050506040513d604081101561438357600080fd5b50805160209091015190925090506000856143a6576143a183614d30565b6143af565b6001600160801b035b90506000866143c6576143c183614d30565b6143cf565b6001600160801b035b90506000826001600160801b031611806143f257506000816001600160801b0316115b156144cc57604080516309e3d67b60e31b81526001600160a01b038a8116600483015260028e810b60248401528d900b60448301526001600160801b0385811660648401528416608483015282517f000000000000000000000000000000000000000000000000000000000000000090911692634f1eb3d89260a480820193918290030181600087803b15801561448857600080fd5b505af115801561449c573d6000803e3d6000fd5b505050506040513d60408110156144b257600080fd5b5080516020909101516001600160801b0391821697501694505b505050509550959350505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663665a17c56040518163ffffffff1660e01b815260040160206040518083038186803b15801561453557600080fd5b505afa158015614549573d6000803e3d6000fd5b505050506040513d602081101561455f57600080fd5b5051604080516337792e1d60e11b815290519192506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691636ef25c3a916004808301926020929190829003018186803b1580156145c757600080fd5b505afa1580156145db573d6000803e3d6000fd5b505050506040513d60208110156145f157600080fd5b50519050811580159061460e57506008546001600160a01b031615155b156146cd57831561467057600854614670906001600160a01b031661463f670de0b6b3a7640000610af88887613491565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906134ea565b82156146cd576008546146cd906001600160a01b031661469c670de0b6b3a7640000610af88787613491565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906134ea565b80156139d3576009546000906001600160a01b031615614771577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663acc8247d6040518163ffffffff1660e01b815260040160206040518083038186803b15801561474057600080fd5b505afa158015614754573d6000803e3d6000fd5b505050506040513d602081101561476a57600080fd5b505161477b565b670de0b6b3a76400005b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663469048406040518163ffffffff1660e01b815260040160206040518083038186803b1580156147d857600080fd5b505afa1580156147ec573d6000803e3d6000fd5b505050506040513d602081101561480257600080fd5b5051905085156148c6576000614824670de0b6b3a7640000610af88987613491565b9050600061483e670de0b6b3a7640000610af88487613491565b9050600061484c8383613d9d565b90506148826001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001685846134ea565b80156148c2576009546148c2906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836134ea565b5050505b84156149865760006148e4670de0b6b3a7640000610af88887613491565b905060006148fe670de0b6b3a7640000610af88487613491565b9050600061490c8383613d9d565b90506149426001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001685846134ea565b801561498257600954614982906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169116836134ea565b5050505b505050505050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b1580156149ea57600080fd5b505afa1580156149fe573d6000803e3d6000fd5b505050506040513d60e0811015614a1457600080fd5b50516040805163986cfba360e01b8152600289900b6004820152905191925073a7e0fb32618818cfcaba025a3af3544c17ca84f691636098fd4a918491849163986cfba3916024808301926020929190829003018186803b158015614a7857600080fd5b505af4158015614a8c573d6000803e3d6000fd5b505050506040513d6020811015614aa257600080fd5b50516040805163986cfba360e01b815260028b900b6004820152905173a7e0fb32618818cfcaba025a3af3544c17ca84f69163986cfba3916024808301926020929190829003018186803b158015614af957600080fd5b505af4158015614b0d573d6000803e3d6000fd5b505050506040513d6020811015614b2357600080fd5b5051604080516001600160e01b031960e087901b1681526001600160a01b0394851660048201529284166024840152921660448201526064810188905260848101879052905160a4808301926020929190829003018186803b158015614b8857600080fd5b505af4158015614b9c573d6000803e3d6000fd5b505050506040513d6020811015614bb257600080fd5b50519695505050505050565b6000806001600160801b038316156142ca5760408051306020808301829052835180840382018152838501948590526302abf8a760e61b909452604483018281526064840183905260028a810b608486015289900b60a48501526001600160801b03881660c485015260c060e48501908152855161010486015285516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169663aafe29c09686958e958e958e9591939092610124909101919085019080838360005b83811015614ca0578181015183820152602001614c88565b50505050905090810190601f168015614ccd5780820380516001836020036101000a031916815260200191505b50975050505050505050606060405180830381600087803b158015614cf157600080fd5b505af1158015614d05573d6000803e3d6000fd5b505050506040513d6060811015614d1b57600080fd5b50805160209091015190969095509350505050565b60006001600160801b03821115614d7a576040805162461bcd60e51b815260206004820152600960248201526824ab1718991c2fa7a360b91b604482015290519081900360640190fd5b5090565b6000614dd3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e2f9092919063ffffffff16565b80519091501561353c57808060200190516020811015614df257600080fd5b505161353c5760405162461bcd60e51b815260040180806020018281038252602a815260200180615240602a913960400191505060405180910390fd5b6060614e3e8484600085614e46565b949350505050565b606082471015614e875760405162461bcd60e51b81526004018080602001828103825260268152602001806151046026913960400191505060405180910390fd5b614e9085614fa1565b614ee1576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310614f1f5780518252601f199092019160209182019101614f00565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114614f81576040519150601f19603f3d011682016040523d82523d6000602084013e614f86565b606091505b5091509150614f96828286614fa7565b979650505050505050565b3b151590565b60608315614fb6575081610eee565b825115614fc65782518084602001fd5b60405162461bcd60e51b815260206004820181815284516024840152845185939192839260440191908501908083836000831561393657818101518382015260200161391e56fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573735265656e7472616e637947756172643a207265656e7472616e742063616c6c0045524332303a206275726e20616d6f756e7420657863656564732062616c616e63654f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737349562e726562616c616e63653a206261736520706f736974696f6e20696e76616c696445524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c49562e63757272656e745469636b3a2074686520706f6f6c206973206c6f636b6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657245524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737349562e726562616c616e63653a206964656e746963616c20706f736974696f6e735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656449562e726562616c616e63653a206c696d697420706f736974696f6e20696e76616c696445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220e2aa6d6d66579ffe132dfe562d7a7dea7ac9f2381ec76dca97937b5a075b3bc764736f6c634300070600334f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573738be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e049562e636f6e7374727563746f723a206e6f20616c6c6f77656420746f6b656e73a2646970667358221220f001da2d4bda9e8609058e5568a6e50abd1625193dec8134e78e1a534ffe675c64736f6c63430007060033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.