Overview
ETH Balance
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18299874 | 1 hr ago | 0 ETH | ||||
18299874 | 1 hr ago | 0 ETH | ||||
18299207 | 2 hrs ago | 0 ETH | ||||
18299207 | 2 hrs ago | 0 ETH | ||||
18299207 | 2 hrs ago | 0 ETH | ||||
18299207 | 2 hrs ago | 0 ETH | ||||
18298360 | 2 hrs ago | 0 ETH | ||||
18298360 | 2 hrs ago | 0 ETH | ||||
18296189 | 4 hrs ago | 0 ETH | ||||
18296189 | 4 hrs ago | 0 ETH | ||||
18296189 | 4 hrs ago | 0 ETH | ||||
18296189 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH | ||||
18296085 | 4 hrs ago | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
ICHIVaultFactory
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 { IICHIVaultFactory } from "../interfaces/IICHIVaultFactory.sol"; import { IAlgebraFactory } from "@cryptoalgebra/v1.9-core/contracts/interfaces/IAlgebraFactory.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import { ICHIVaultDeployer } from "./lib/ICHIVaultDeployer.sol"; import { IAlgebraPool } from "@cryptoalgebra/v1.9-core/contracts/interfaces/IAlgebraPool.sol"; import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; contract ICHIVaultFactory is IICHIVaultFactory, ReentrancyGuard, Ownable { using SafeMath for uint256; address constant NULL_ADDRESS = address(0); uint256 constant DEFAULT_AMM_FEE = 0; // 0% uint256 constant DEFAULT_BASE_FEE = 2 * 10 ** 17; // 20% uint256 constant DEFAULT_BASE_FEE_SPLIT = 5 * 10 ** 17; // 50% uint256 constant PRECISION = 10 ** 18; uint32 constant DEFAULT_TWAP_PERIOD = 60 minutes; address public immutable override algebraFactory; address public override feeRecipient; uint256 public override ammFee; uint256 public override baseFee; uint256 public override baseFeeSplit; mapping(bytes32 => address) public getICHIVault; address[] public allVaults; /** @notice creates an instance of ICHIVaultFactory @param _algebraFactory Algebra V1 factory */ constructor(address _algebraFactory) { require(_algebraFactory != NULL_ADDRESS, "IVF.constructor: zero address"); algebraFactory = _algebraFactory; feeRecipient = msg.sender; ammFee = DEFAULT_AMM_FEE; baseFee = DEFAULT_BASE_FEE; baseFeeSplit = DEFAULT_BASE_FEE_SPLIT; emit DeployICHIVaultFactory(msg.sender, _algebraFactory); } /** @notice Creates ICHIVault for given tokenA/tokenB/fee, possibly making Uniswap V3 pool. Controls one-sided/two-sided liquidity provision via AllowToken. @param tokenA TokenA of the Algebra V1 pool. @param allowTokenA If true, tokenA is accepted during deposit. @param tokenB TokenB of the Algebra V1 pool. @param allowTokenB If true, tokenB is accepted during deposit. @return ichiVault Address of the newly created ICHIVault. */ function createICHIVault( address tokenA, bool allowTokenA, address tokenB, bool allowTokenB ) external override nonReentrant returns (address ichiVault) { require(tokenA != tokenB, "IVF.createICHIVault: identical tokens"); (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); (bool allowToken0, bool allowToken1) = tokenA < tokenB ? (allowTokenA, allowTokenB) : (allowTokenB, allowTokenA); require(token0 != NULL_ADDRESS, "IVF.createICHIVault: zero address"); require(allowTokenA || allowTokenB, "IVF.createICHIVault: no allowed tokens"); require( getICHIVault[genKey(msg.sender, token0, token1, allowToken0, allowToken1)] == NULL_ADDRESS, "IVF.createICHIVault: vault exists" ); address pool = IAlgebraFactory(algebraFactory).poolByPair(tokenA, tokenB); require(pool != NULL_ADDRESS, "IVF.createICHIVault: pool must exist"); (, , , , , , bool unlocked) = IAlgebraPool(pool).globalState(); require(unlocked, "IVF.createICHIVault: pool is locked"); ichiVault = ICHIVaultDeployer.createICHIVault( pool, token0, allowToken0, token1, allowToken1, DEFAULT_TWAP_PERIOD, allVaults.length ); getICHIVault[genKey(msg.sender, token0, token1, allowToken0, allowToken1)] = ichiVault; getICHIVault[genKey(msg.sender, token1, token0, allowToken1, allowToken0)] = ichiVault; // populate mapping in the reverse direction allVaults.push(ichiVault); emit ICHIVaultCreated(msg.sender, ichiVault, token0, allowToken0, token1, allowToken1, allVaults.length); } /** @notice Sets the fee recipient account address, where portion of the collected swap fees will be distributed @dev onlyOwner @param _feeRecipient The fee recipient account address */ function setFeeRecipient(address _feeRecipient) external override onlyOwner { require(_feeRecipient != NULL_ADDRESS, "IVF.setFeeRecipient: zero address"); feeRecipient = _feeRecipient; emit FeeRecipient(msg.sender, _feeRecipient); } /** @notice Sets fee percentage taken from pool's swap fees, used for AMM external incentives. @dev Access restricted to the owner. @param _ammFee Fee percentage from pool's swap fees for AMM. */ function setAmmFee(uint256 _ammFee) external override onlyOwner { require(baseFee.add(_ammFee) <= PRECISION, "IVF.setAmmFee: fees must be <= 10**18"); ammFee = _ammFee; emit AmmFee(msg.sender, _ammFee); } /** @notice Sets fee percentage from pool's swap fees, distributed to feeRecipient and affiliates. @dev Access restricted to the owner. @param _baseFee Fee percentage taken from pool's swap fees. */ function setBaseFee(uint256 _baseFee) external override onlyOwner { require(ammFee.add(_baseFee) <= PRECISION, "IVF.setBaseFee: fees must be <= 10**18"); baseFee = _baseFee; emit BaseFee(msg.sender, _baseFee); } /** @notice Sets fee split ratio between feeRecipient and affiliates. Ratio as (baseFeeSplit)/(100 - baseFeeSplit). E.g., for a 20/80 split, set baseFeeSplit to 20. @dev Accessible only by the owner. @param _baseFeeSplit Fee split ratio between feeRecipient and affiliates. */ function setBaseFeeSplit(uint256 _baseFeeSplit) external override onlyOwner { require(_baseFeeSplit <= PRECISION, "IVF.setBaseFeeSplit: must be <= 10**18"); baseFeeSplit = _baseFeeSplit; emit BaseFeeSplit(msg.sender, _baseFeeSplit); } /** * @notice generate a key for getIchiVault * @param deployer vault creator * @param token0 the first of two tokens in the vault * @param token1 the second of two tokens in the vault * @param allowToken0 allow deposits * @param allowToken1 allow deposits * @return key generated key */ function genKey( address deployer, address token0, address token1, bool allowToken0, bool allowToken1 ) public pure override returns (bytes32 key) { key = keccak256(abi.encodePacked(deployer, token0, token1, allowToken0, allowToken1)); } }
// 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 { 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: 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/ICHIVaultDeployer.sol": { "ICHIVaultDeployer": "0xe2381b5afae99b899596bc550184a080daa31f26" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_algebraFactory","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"ammFee","type":"uint256"}],"name":"AmmFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseFee","type":"uint256"}],"name":"BaseFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"baseFeeSplit","type":"uint256"}],"name":"BaseFeeSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"algebraFactory","type":"address"}],"name":"DeployICHIVaultFactory","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"FeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"ichiVault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenA","type":"address"},{"indexed":false,"internalType":"bool","name":"allowTokenA","type":"bool"},{"indexed":false,"internalType":"address","name":"tokenB","type":"address"},{"indexed":false,"internalType":"bool","name":"allowTokenB","type":"bool"},{"indexed":false,"internalType":"uint256","name":"count","type":"uint256"}],"name":"ICHIVaultCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"algebraFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allVaults","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ammFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseFeeSplit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"bool","name":"allowTokenA","type":"bool"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"bool","name":"allowTokenB","type":"bool"}],"name":"createICHIVault","outputs":[{"internalType":"address","name":"ichiVault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"bool","name":"allowToken0","type":"bool"},{"internalType":"bool","name":"allowToken1","type":"bool"}],"name":"genKey","outputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"getICHIVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ammFee","type":"uint256"}],"name":"setAmmFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseFee","type":"uint256"}],"name":"setBaseFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseFeeSplit","type":"uint256"}],"name":"setBaseFeeSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a060405234801561001057600080fd5b506040516112a73803806112a78339818101604052602081101561003357600080fd5b505160016000908155610044610173565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b0381166100ed576040805162461bcd60e51b815260206004820152601d60248201527f4956462e636f6e7374727563746f723a207a65726f2061646472657373000000604482015290519081900360640190fd5b6001600160601b0319606082901b16608052600280546001600160a01b0319163390811790915560006003556702c68af0bb1400006004556706f05b59d3b20000600555604080516001600160a01b038416815290517f18e8698e841d62b36528b0cdc3a69558682cb331bd99cd50ffc7a6107b7fe13a9181900360200190a250610177565b3390565b60805160601c61110e6101996000398061073c5280610c9e525061110e6000f3fe608060405234801561001057600080fd5b50600436106101005760003560e01c8063715018a611610097578063a7b64b0411610066578063a7b64b0414610272578063acc8247d1461027a578063e74b981b14610282578063f2fde38b146102a857610100565b8063715018a6146102285780638da5cb5b146102305780638f43ee24146102385780639094a91e1461025557610100565b806354a88073116100d357806354a88073146101bd5780635f715016146101da578063665a17c5146102185780636ef25c3a1461022057610100565b80630d4a4e5214610105578063468606981461015d578063469048401461017c57806350309615146101a0575b600080fd5b61014b600480360360a081101561011b57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101351515906080013515156102ce565b60408051918252519081900360200190f35b61017a6004803603602081101561017357600080fd5b5035610336565b005b61018461042a565b604080516001600160a01b039092168252519081900360200190f35b610184600480360360208110156101b657600080fd5b5035610439565b61017a600480360360208110156101d357600080fd5b5035610454565b610184600480360360808110156101f057600080fd5b506001600160a01b038135811691602081013515159160408201351690606001351515610548565b61014b610ac4565b61014b610aca565b61017a610ad0565b610184610b7c565b61017a6004803603602081101561024e57600080fd5b5035610b8b565b6101846004803603602081101561026b57600080fd5b5035610c72565b610184610c9c565b61014b610cc0565b61017a6004803603602081101561029857600080fd5b50356001600160a01b0316610cc6565b61017a600480360360208110156102be57600080fd5b50356001600160a01b0316610dc4565b604080516bffffffffffffffffffffffff19606097881b811660208084019190915296881b811660348301529490961b909316604886015290151560f890811b605c860152901515901b605d8401528051603e818503018152605e9093019052815191012090565b61033e610ec7565b6001600160a01b031661034f610b7c565b6001600160a01b031614610398576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b600354670de0b6b3a7640000906103af9083610ecb565b11156103ec5760405162461bcd60e51b815260040180806020018281038252602681526020018061104a6026913960400191505060405180910390fd5b600481905560408051828152905133917f3eebe58c525adbccc2701122aa3f72afe1db9f1eaeb6f20c7500332042d3d0ae919081900360200190a250565b6002546001600160a01b031681565b6006602052600090815260409020546001600160a01b031681565b61045c610ec7565b6001600160a01b031661046d610b7c565b6001600160a01b0316146104b6576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b600454670de0b6b3a7640000906104cd9083610ecb565b111561050a5760405162461bcd60e51b8152600401808060200182810382526025815260200180610f956025913960400191505060405180910390fd5b600381905560408051828152905133917fbab3d5a1afa9cf183465773f045bb703420b716528d2cc0ded25b14c9cbf789f919081900360200190a250565b6000600260005414156105a2576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026000556001600160a01b0385811690841614156105f25760405162461bcd60e51b81526004018080602001828103825260258152602001806110b46025913960400191505060405180910390fd5b600080846001600160a01b0316876001600160a01b031610610615578487610618565b86855b91509150600080866001600160a01b0316896001600160a01b03161061063f578588610642565b87865b90925090506001600160a01b03841661068c5760405162461bcd60e51b8152600401808060200182810382526021815260200180610f4e6021913960400191505060405180910390fd5b87806106955750855b6106d05760405162461bcd60e51b81526004018080602001828103825260268152602001806110246026913960400191505060405180910390fd5b60006006816106e233888888886102ce565b81526020810191909152604001600020546001600160a01b0316146107385760405162461bcd60e51b8152600401808060200182810382526021815260200180610f2d6021913960400191505060405180910390fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d9a641e18b8a6040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b031681526020019250505060206040518083038186803b1580156107b857600080fd5b505afa1580156107cc573d6000803e3d6000fd5b505050506040513d60208110156107e257600080fd5b505190506001600160a01b03811661082b5760405162461bcd60e51b81526004018080602001828103825260248152602001806110906024913960400191505060405180910390fd5b6000816001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561086657600080fd5b505afa15801561087a573d6000803e3d6000fd5b505050506040513d60e081101561089057600080fd5b5060c001519050806108d35760405162461bcd60e51b81526004018080602001828103825260238152602001806110016023913960400191505060405180910390fd5b600754604080516356f3618560e11b81526001600160a01b038086166004830152808a1660248301528715156044830152881660648201528515156084820152610e1060a482015260c48101929092525173e2381b5afae99b899596bc550184a080daa31f269163ade6c30a9160e4808301926020929190829003018186803b15801561095f57600080fd5b505af4158015610973573d6000803e3d6000fd5b505050506040513d602081101561098957600080fd5b50519650866006600061099f338a8a8a8a6102ce565b815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555086600660006109e333898b898b6102ce565b81526020808201929092526040908101600090812080546001600160a01b039586166001600160a01b03199182161790915560078054600181018255928190527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68890920180548d8716921682179055905482519182528a851693820193909352871515818301529288166060840152851515608084015260a08301919091525133917fc40564e4b61a849e6f9fd666c2109aa6ceffc5a019f87d4d3e0eaaf807b0783e919081900360c00190a2505060016000555092979650505050505050565b60035481565b60045481565b610ad8610ec7565b6001600160a01b0316610ae9610b7c565b6001600160a01b031614610b32576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6001546001600160a01b031690565b610b93610ec7565b6001600160a01b0316610ba4610b7c565b6001600160a01b031614610bed576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b670de0b6b3a7640000811115610c345760405162461bcd60e51b8152600401808060200182810382526026815260200180610fdb6026913960400191505060405180910390fd5b600581905560408051828152905133917ff23c377b67694a17208802cc028e3c91e1a9bbebb5c14cc17d6cea366374b457919081900360200190a250565b60078181548110610c8257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60055481565b610cce610ec7565b6001600160a01b0316610cdf610b7c565b6001600160a01b031614610d28576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b6001600160a01b038116610d6d5760405162461bcd60e51b8152600401808060200182810382526021815260200180610fba6021913960400191505060405180910390fd5b600280546001600160a01b0383166001600160a01b03199091168117909155604080519182525133917fa3c35be2df207ef65dd1fa9d8feba470160e2a6d259f30f2ed070c69b7ec4576919081900360200190a250565b610dcc610ec7565b6001600160a01b0316610ddd610b7c565b6001600160a01b031614610e26576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b6001600160a01b038116610e6b5760405162461bcd60e51b8152600401808060200182810382526026815260200180610f6f6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b600082820183811015610f25576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b939250505056fe4956462e637265617465494348495661756c743a207661756c74206578697374734956462e637265617465494348495661756c743a207a65726f20616464726573734f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734956462e736574416d6d4665653a2066656573206d757374206265203c3d2031302a2a31384956462e736574466565526563697069656e743a207a65726f20616464726573734956462e7365744261736546656553706c69743a206d757374206265203c3d2031302a2a31384956462e637265617465494348495661756c743a20706f6f6c206973206c6f636b65644956462e637265617465494348495661756c743a206e6f20616c6c6f77656420746f6b656e734956462e736574426173654665653a2066656573206d757374206265203c3d2031302a2a31384f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724956462e637265617465494348495661756c743a20706f6f6c206d7573742065786973744956462e637265617465494348495661756c743a206964656e746963616c20746f6b656e73a2646970667358221220ccc598a4ea6357cf0c2830996a4aa04b323e34007ba585501c2b70e1a2c22ed064736f6c63430007060033000000000000000000000000622b2c98123d303ae067db4925cd6282b3a08d0f
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101005760003560e01c8063715018a611610097578063a7b64b0411610066578063a7b64b0414610272578063acc8247d1461027a578063e74b981b14610282578063f2fde38b146102a857610100565b8063715018a6146102285780638da5cb5b146102305780638f43ee24146102385780639094a91e1461025557610100565b806354a88073116100d357806354a88073146101bd5780635f715016146101da578063665a17c5146102185780636ef25c3a1461022057610100565b80630d4a4e5214610105578063468606981461015d578063469048401461017c57806350309615146101a0575b600080fd5b61014b600480360360a081101561011b57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101351515906080013515156102ce565b60408051918252519081900360200190f35b61017a6004803603602081101561017357600080fd5b5035610336565b005b61018461042a565b604080516001600160a01b039092168252519081900360200190f35b610184600480360360208110156101b657600080fd5b5035610439565b61017a600480360360208110156101d357600080fd5b5035610454565b610184600480360360808110156101f057600080fd5b506001600160a01b038135811691602081013515159160408201351690606001351515610548565b61014b610ac4565b61014b610aca565b61017a610ad0565b610184610b7c565b61017a6004803603602081101561024e57600080fd5b5035610b8b565b6101846004803603602081101561026b57600080fd5b5035610c72565b610184610c9c565b61014b610cc0565b61017a6004803603602081101561029857600080fd5b50356001600160a01b0316610cc6565b61017a600480360360208110156102be57600080fd5b50356001600160a01b0316610dc4565b604080516bffffffffffffffffffffffff19606097881b811660208084019190915296881b811660348301529490961b909316604886015290151560f890811b605c860152901515901b605d8401528051603e818503018152605e9093019052815191012090565b61033e610ec7565b6001600160a01b031661034f610b7c565b6001600160a01b031614610398576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b600354670de0b6b3a7640000906103af9083610ecb565b11156103ec5760405162461bcd60e51b815260040180806020018281038252602681526020018061104a6026913960400191505060405180910390fd5b600481905560408051828152905133917f3eebe58c525adbccc2701122aa3f72afe1db9f1eaeb6f20c7500332042d3d0ae919081900360200190a250565b6002546001600160a01b031681565b6006602052600090815260409020546001600160a01b031681565b61045c610ec7565b6001600160a01b031661046d610b7c565b6001600160a01b0316146104b6576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b600454670de0b6b3a7640000906104cd9083610ecb565b111561050a5760405162461bcd60e51b8152600401808060200182810382526025815260200180610f956025913960400191505060405180910390fd5b600381905560408051828152905133917fbab3d5a1afa9cf183465773f045bb703420b716528d2cc0ded25b14c9cbf789f919081900360200190a250565b6000600260005414156105a2576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026000556001600160a01b0385811690841614156105f25760405162461bcd60e51b81526004018080602001828103825260258152602001806110b46025913960400191505060405180910390fd5b600080846001600160a01b0316876001600160a01b031610610615578487610618565b86855b91509150600080866001600160a01b0316896001600160a01b03161061063f578588610642565b87865b90925090506001600160a01b03841661068c5760405162461bcd60e51b8152600401808060200182810382526021815260200180610f4e6021913960400191505060405180910390fd5b87806106955750855b6106d05760405162461bcd60e51b81526004018080602001828103825260268152602001806110246026913960400191505060405180910390fd5b60006006816106e233888888886102ce565b81526020810191909152604001600020546001600160a01b0316146107385760405162461bcd60e51b8152600401808060200182810382526021815260200180610f2d6021913960400191505060405180910390fd5b60007f000000000000000000000000622b2c98123d303ae067db4925cd6282b3a08d0f6001600160a01b031663d9a641e18b8a6040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b031681526020019250505060206040518083038186803b1580156107b857600080fd5b505afa1580156107cc573d6000803e3d6000fd5b505050506040513d60208110156107e257600080fd5b505190506001600160a01b03811661082b5760405162461bcd60e51b81526004018080602001828103825260248152602001806110906024913960400191505060405180910390fd5b6000816001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561086657600080fd5b505afa15801561087a573d6000803e3d6000fd5b505050506040513d60e081101561089057600080fd5b5060c001519050806108d35760405162461bcd60e51b81526004018080602001828103825260238152602001806110016023913960400191505060405180910390fd5b600754604080516356f3618560e11b81526001600160a01b038086166004830152808a1660248301528715156044830152881660648201528515156084820152610e1060a482015260c48101929092525173e2381b5afae99b899596bc550184a080daa31f269163ade6c30a9160e4808301926020929190829003018186803b15801561095f57600080fd5b505af4158015610973573d6000803e3d6000fd5b505050506040513d602081101561098957600080fd5b50519650866006600061099f338a8a8a8a6102ce565b815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b0316021790555086600660006109e333898b898b6102ce565b81526020808201929092526040908101600090812080546001600160a01b039586166001600160a01b03199182161790915560078054600181018255928190527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68890920180548d8716921682179055905482519182528a851693820193909352871515818301529288166060840152851515608084015260a08301919091525133917fc40564e4b61a849e6f9fd666c2109aa6ceffc5a019f87d4d3e0eaaf807b0783e919081900360c00190a2505060016000555092979650505050505050565b60035481565b60045481565b610ad8610ec7565b6001600160a01b0316610ae9610b7c565b6001600160a01b031614610b32576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6001546001600160a01b031690565b610b93610ec7565b6001600160a01b0316610ba4610b7c565b6001600160a01b031614610bed576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b670de0b6b3a7640000811115610c345760405162461bcd60e51b8152600401808060200182810382526026815260200180610fdb6026913960400191505060405180910390fd5b600581905560408051828152905133917ff23c377b67694a17208802cc028e3c91e1a9bbebb5c14cc17d6cea366374b457919081900360200190a250565b60078181548110610c8257600080fd5b6000918252602090912001546001600160a01b0316905081565b7f000000000000000000000000622b2c98123d303ae067db4925cd6282b3a08d0f81565b60055481565b610cce610ec7565b6001600160a01b0316610cdf610b7c565b6001600160a01b031614610d28576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b6001600160a01b038116610d6d5760405162461bcd60e51b8152600401808060200182810382526021815260200180610fba6021913960400191505060405180910390fd5b600280546001600160a01b0383166001600160a01b03199091168117909155604080519182525133917fa3c35be2df207ef65dd1fa9d8feba470160e2a6d259f30f2ed070c69b7ec4576919081900360200190a250565b610dcc610ec7565b6001600160a01b0316610ddd610b7c565b6001600160a01b031614610e26576040805162461bcd60e51b81526020600482018190526024820152600080516020611070833981519152604482015290519081900360640190fd5b6001600160a01b038116610e6b5760405162461bcd60e51b8152600401808060200182810382526026815260200180610f6f6026913960400191505060405180910390fd5b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b600082820183811015610f25576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b939250505056fe4956462e637265617465494348495661756c743a207661756c74206578697374734956462e637265617465494348495661756c743a207a65726f20616464726573734f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734956462e736574416d6d4665653a2066656573206d757374206265203c3d2031302a2a31384956462e736574466565526563697069656e743a207a65726f20616464726573734956462e7365744261736546656553706c69743a206d757374206265203c3d2031302a2a31384956462e637265617465494348495661756c743a20706f6f6c206973206c6f636b65644956462e637265617465494348495661756c743a206e6f20616c6c6f77656420746f6b656e734956462e736574426173654665653a2066656573206d757374206265203c3d2031302a2a31384f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724956462e637265617465494348495661756c743a20706f6f6c206d7573742065786973744956462e637265617465494348495661756c743a206964656e746963616c20746f6b656e73a2646970667358221220ccc598a4ea6357cf0c2830996a4aa04b323e34007ba585501c2b70e1a2c22ed064736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000622b2c98123d303ae067db4925cd6282b3a08d0f
-----Decoded View---------------
Arg [0] : _algebraFactory (address): 0x622b2c98123D303ae067DB4925CD6282B3A08D0F
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000622b2c98123d303ae067db4925cd6282b3a08d0f
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.