Contract
0xbd712D4dbd4b8d0cD2A98aDb0f9fC2928031b16F
13
Contract Overview
Balance:
0 ETH
ETH Value:
$0.00
My Name Tag:
Not Available, login to update
Txn Hash | Method |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x2e9a57e237afd66d7499d2219a12af084b4d8cbac468ae2ef8298424cfa96127 | Set Governance | 4553001 | 43 days 5 hrs ago | 0x1e3881227010c8dcdfa2f11833d3d70a00893f94 | IN | 0xbd712d4dbd4b8d0cd2a98adb0f9fc2928031b16f | 0 ETH | 0.000026585636 | |
0x407ee74b01799dcfa7f698c33abb8803c479de4258607452a95ba01539371040 | Set Unipilot Det... | 4552988 | 43 days 5 hrs ago | 0x1e3881227010c8dcdfa2f11833d3d70a00893f94 | IN | 0xbd712d4dbd4b8d0cd2a98adb0f9fc2928031b16f | 0 ETH | 0.000028221554 | |
0x67efe9d67f5d0164882c20b22377ce02ab7b0e1ded3aaeada16c1df87e946d98 | Create Vault | 556231 | 121 days 7 hrs ago | 0x3a88be99c21f93e55a5561d0d89eb9f94e37a7a0 | IN | 0xbd712d4dbd4b8d0cd2a98adb0f9fc2928031b16f | 0 ETH | 0.0064199385 | |
0xb17a91f8461139f261d6134099064d4627efd2dc0b985de9582e8f16a534c9b9 | 0x60806040 | 209294 | 143 days 5 hrs ago | 0x73da331e6e5ad4959512577dd01e85f8942f359c | IN | Create: UnipilotPassiveFactory | 0 ETH | 0.0464823117 |
[ Download CSV Export ]
Latest 1 internal transaction
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x67efe9d67f5d0164882c20b22377ce02ab7b0e1ded3aaeada16c1df87e946d98 | 556231 | 121 days 7 hrs ago | 0xbd712d4dbd4b8d0cd2a98adb0f9fc2928031b16f | Contract Creation | 0 ETH |
[ Download CSV Export ]
Contract Name:
UnipilotPassiveFactory
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity ^0.7.6; import "./UnipilotPassiveVault.sol"; import "./interfaces/IUnipilotFactory.sol"; import "@cryptoalgebra/core/contracts/interfaces/IAlgebraFactory.sol"; import "@cryptoalgebra/core/contracts/interfaces/IAlgebraPool.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; /// @title Unipilot Passive Factory /// @author 0xMudassir & 721Orbit /// @notice Deploys Unipilot vaults for any uniswap v3 pair by any user. /// passive liquidity managament strategy will be used in these vaults /// all passive vaults can be managed by any user contract UnipilotPassiveFactory is IUnipilotFactory { address private WETH; address private governance; address private strategy; address private indexFund; uint8 private swapPercentage; uint8 private indexFundPercentage; IAlgebraFactory private algebraFactory; constructor( address _algebraFactory, address _governance, address _uniStrategy, address _indexFund, address _WETH, uint8 _indexFundPercentage, uint8 _swapPercentage ) { governance = _governance; strategy = _uniStrategy; algebraFactory = IAlgebraFactory(_algebraFactory); indexFund = _indexFund; WETH = _WETH; indexFundPercentage = _indexFundPercentage; swapPercentage = _swapPercentage; } mapping(address => mapping(address => mapping(uint16 => address))) public vaults; modifier onlyGovernance() { require(msg.sender == governance); _; } /// @inheritdoc IUnipilotFactory function getUnipilotDetails() external view override returns ( address, address, address, uint8, uint8 ) { return ( governance, strategy, indexFund, indexFundPercentage, swapPercentage ); } /// @inheritdoc IUnipilotFactory function createVault( address _tokenA, address _tokenB, uint16 _vaultStrategy, uint160 _sqrtPriceX96, string memory _name, string memory _symbol ) external override returns (address _vault) { require(_tokenA != _tokenB); (address token0, address token1) = _tokenA < _tokenB ? (_tokenA, _tokenB) : (_tokenB, _tokenA); address pool = algebraFactory.poolByPair(token0, token1); if (pool != address(0)) { require(vaults[token0][token1][0] == address(0)); } else { pool = algebraFactory.createPool(token0, token1); IAlgebraPool(pool).initialize(_sqrtPriceX96); } ERC20 token0Instance = ERC20(token0); ERC20 token1Instance = ERC20(token1); _name = string( abi.encodePacked( "Unipilot ", token0Instance.symbol(), "/", token1Instance.symbol(), " Passive" " Vault" ) ); _symbol = string( abi.encodePacked( "ULP", "-", token0Instance.symbol(), "/", token1Instance.symbol(), "-", "PV" ) ); _vault = address( new UnipilotPassiveVault{ salt: keccak256(abi.encodePacked(_tokenA, _tokenB)) }(pool, address(this), WETH, _name, _symbol) ); vaults[token0][token1][0] = _vault; vaults[token1][token0][0] = _vault; // populate mapping in the reverse direction emit VaultCreated(token0, token1, _vaultStrategy, _vault); } /// @notice Updates the governance of all Unipilot passive vaults /// @dev Must be called by the current governance /// @param _newGovernance The new governance of the Unipilot passive factory function setGovernance(address _newGovernance) external onlyGovernance { require(_newGovernance != address(0)); emit GovernanceChanged(governance, _newGovernance); governance = _newGovernance; } /// @notice Updates all the necessary Unipilot details used in passive vaults /// @dev Must be called by the current governance /// @param _strategy Unipilot strategy address /// @param _indexFund Unipilot index fund account /// @param _swapPercentage Percentage of swap during readjust liquidity /// @param _indexFundPercentage Percentage of fees for index fund function setUnipilotDetails( address _strategy, address _indexFund, uint8 _swapPercentage, uint8 _indexFundPercentage ) external onlyGovernance { require(_strategy != address(0) && _indexFund != address(0)); require(_swapPercentage > 0 && _swapPercentage < 100); require(_indexFundPercentage > 0 && _indexFundPercentage < 100); strategy = _strategy; indexFund = _indexFund; indexFundPercentage = _indexFundPercentage; swapPercentage = _swapPercentage; } }
//SPDX-License-Identifier: MIT pragma solidity 0.7.6; pragma abicoder v2; import "./libraries/TransferHelper.sol"; import "./interfaces/external/IWETH9.sol"; import "./interfaces/IUnipilotVault.sol"; import "./interfaces/IUnipilotStrategy.sol"; import "./interfaces/IUnipilotFactory.sol"; import "./libraries/UniswapLiquidityManagement.sol"; import "./libraries/SafeCastExtended.sol"; import "./libraries/UniswapPoolActions.sol"; import "@openzeppelin/contracts/drafts/ERC20Permit.sol"; /// @title Unipilot Passive Vault /// @author 0xMudassir & 721Orbit /// @notice Passive liquidity managment contract that handles liquidity of any Uniswap V3 pool & earn fees /// @dev UnipilotPassiveVault always maintains 2 range orders on Uniswap V3, /// base order: The main liquidity range -- where the majority of LP capital sits /// limit order: A single token range -- depending on which token it holds more of after the base order was placed. /// @dev The vault readjustment function can be called by anyone to ensure /// the liquidity of vault remains in the most optimum range contract UnipilotPassiveVault is ERC20Permit, IUnipilotVault { using SafeCastExtended for uint256; using LowGasSafeMath for uint256; using UniswapPoolActions for IAlgebraPool; using UniswapLiquidityManagement for IAlgebraPool; IERC20 private immutable token0; IERC20 private immutable token1; int24 private immutable tickSpacing; address private immutable WETH; IUnipilotFactory private immutable unipilotFactory; uint256 internal constant MIN_INITIAL_SHARES = 1e3; TicksData public ticksData; IAlgebraPool private pool; uint96 private _unlocked = 1; modifier nonReentrant() { require(_unlocked == 1); _unlocked = 2; _; _unlocked = 1; } modifier checkDeviation() { (, address strategy, , , ) = getProtocolDetails(); IUnipilotStrategy(strategy).checkDeviation(address(pool)); _; } constructor( address _pool, address _unipilotFactory, address _WETH, string memory _name, string memory _symbol ) ERC20Permit(_name) ERC20(_name, _symbol) { require(_pool != address(0)); require(_WETH != address(0)); require(_unipilotFactory != address(0)); pool = IAlgebraPool(_pool); unipilotFactory = IUnipilotFactory(_unipilotFactory); WETH = _WETH; token0 = IERC20(pool.token0()); token1 = IERC20(pool.token1()); tickSpacing = pool.tickSpacing(); } receive() external payable {} fallback() external payable {} /// @inheritdoc IUnipilotVault function deposit( uint256 amount0Desired, uint256 amount1Desired, address recipient ) external payable override nonReentrant returns ( uint256 lpShares, uint256 amount0, uint256 amount1 ) { require(recipient != address(0)); require(amount0Desired > 0 && amount1Desired > 0); address sender = _msgSender(); uint256 totalSupply = totalSupply(); (lpShares, amount0, amount1) = pool.computeLpShares( false, amount0Desired, amount1Desired, _balance0(), _balance1(), totalSupply, ticksData ); pay(address(token0), sender, address(this), amount0); pay(address(token1), sender, address(this), amount1); if (totalSupply == 0) { // prevent first LP from stealing funds of subsequent LPs // see https://code4rena.com/reports/2022-01-sherlock/#h-01-first-user-can-steal-everyone-elses-tokens require(lpShares > MIN_INITIAL_SHARES, "ML"); setPassivePositions(amount0, amount1); } else { require(lpShares != 0, "IS"); (uint256 amount0Base, uint256 amount1Base) = pool.mintLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, amount0, amount1 ); pool.mintLiquidity( ticksData.rangeTickLower, ticksData.rangeTickUpper, amount0.sub(amount0Base), amount1.sub(amount1Base) ); } if (address(this).balance > 0) TransferHelper.safeTransferETH(sender, address(this).balance); _mint(recipient, lpShares); emit Deposit(sender, recipient, amount0, amount1, lpShares); } /// @inheritdoc IUnipilotVault function withdraw( uint256 liquidity, address recipient, bool refundAsETH ) external override nonReentrant checkDeviation returns (uint256 amount0, uint256 amount1) { require(liquidity > 0); uint256 liquidityShare = FullMath.mulDiv( liquidity, 1e18, totalSupply() ); (uint256 base0, uint256 base1) = burnAndCollect( ticksData.baseTickLower, ticksData.baseTickUpper, liquidityShare ); (uint256 range0, uint256 range1) = burnAndCollect( ticksData.rangeTickLower, ticksData.rangeTickUpper, liquidityShare ); amount0 = base0.add(range0); amount1 = base1.add(range1); uint256 unusedAmount0 = FullMath.mulDiv( _balance0().sub(amount0), liquidity, totalSupply() ); uint256 unusedAmount1 = FullMath.mulDiv( _balance1().sub(amount1), liquidity, totalSupply() ); amount0 = amount0.add(unusedAmount0); amount1 = amount1.add(unusedAmount1); if (amount0 > 0) { transferFunds(refundAsETH, recipient, address(token0), amount0); } if (amount1 > 0) { transferFunds(refundAsETH, recipient, address(token1), amount1); } (base0, base1) = pool.mintLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, _balance0(), _balance1() ); (range0, range1) = pool.mintLiquidity( ticksData.rangeTickLower, ticksData.rangeTickUpper, _balance0(), _balance1() ); _burn(msg.sender, liquidity); emit Withdraw(recipient, liquidity, amount0, amount1); emit CompoundFees(base0.add(range0), base1.add(range1)); } /// @inheritdoc IUnipilotVault function readjustLiquidity(uint8 swapBP) external override nonReentrant checkDeviation { ( uint256 baseAmount0, uint256 baseAmount1, uint256 baseFees0, uint256 baseFees1 ) = pool.burnLiquidity( ticksData.baseTickLower, ticksData.baseTickUpper, address(this) ); ( uint256 rangeAmount0, uint256 rangeAmount1, uint256 rangeFees0, uint256 rangeFees1 ) = pool.burnLiquidity( ticksData.rangeTickLower, ticksData.rangeTickUpper, address(this) ); transferFeesToIF( true, baseFees0.add(rangeFees0), baseFees1.add(rangeFees1) ); uint256 amount0 = baseAmount0.add(rangeAmount0); uint256 amount1 = baseAmount1.add(rangeAmount1); if (amount0 == 0 || amount1 == 0) { bool zeroForOne = amount0 > 0 ? true : false; (, , , , uint8 swapPercentage) = getProtocolDetails(); int256 amountSpecified = zeroForOne ? FullMath.mulDiv(amount0, swapPercentage, 100).toInt256() : FullMath.mulDiv(amount1, swapPercentage, 100).toInt256(); pool.swapToken(address(this), zeroForOne, amountSpecified); } /// @dev to add remaining amounts in contract other than position liquidity amount0 = _balance0(); amount1 = _balance1(); setPassivePositions(amount0, amount1); } /// @inheritdoc IUnipilotVault function algebraMintCallback( uint256 amount0Owed, uint256 amount1Owed, bytes calldata data ) external override { _verifyCallback(); address recipient = _msgSender(); address payer = abi.decode(data, (address)); if (amount0Owed > 0) TransferHelper.safeTransfer( address(token0), recipient, amount0Owed ); if (amount1Owed > 0) TransferHelper.safeTransfer( address(token1), recipient, amount1Owed ); } /// @inheritdoc IUnipilotVault function algebraSwapCallback( int256 amount0, int256 amount1, bytes calldata data ) external override { _verifyCallback(); require(amount0 > 0 || amount1 > 0); bool zeroForOne = abi.decode(data, (bool)); if (zeroForOne) TransferHelper.safeTransfer( address(token0), _msgSender(), uint256(amount0) ); else TransferHelper.safeTransfer( address(token1), _msgSender(), uint256(amount1) ); } /// @notice Calculates the vault's total holdings of TOKEN0 and TOKEN1 - in /// other words, how much of each token the vault would hold if it withdrew /// all its liquidity from Uniswap. /// @dev Updates the position and return the updated reserves, fees & liquidity. /// @return amount0 Amount of token0 in the unipilot vault /// @return amount1 Amount of token1 in the unipilot vault /// @return fees0 Total amount of fees collected by unipilot positions in terms of token0 /// @return fees1 Total amount of fees collected by unipilot positions in terms of token1 /// @return baseLiquidity The total liquidity of the base position /// @return rangeLiquidity The total liquidity of the range position function getPositionDetails() external returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1, uint128 baseLiquidity, uint128 rangeLiquidity ) { return pool.getTotalAmounts(false, ticksData); } /// @notice Returns unipilot vault details /// @return The first of the two tokens of the pool, sorted by address /// @return The second of the two tokens of the pool, sorted by address /// @return The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The address of the Uniswap V3 Pool function getVaultInfo() external view returns ( address, address, uint16, address ) { (, , uint16 fee, , , , ) = pool.globalState(); return (address(token0), address(token1), fee, address(pool)); } /// @dev Amount of token0 held as unused balance. function _balance0() internal view returns (uint256) { return token0.balanceOf(address(this)); } /// @dev Amount of token1 held as unused balance. function _balance1() internal view returns (uint256) { return token1.balanceOf(address(this)); } /// @notice Verify that caller should be the address of a valid Uniswap V3 Pool function _verifyCallback() internal view { require(msg.sender == address(pool)); } function getProtocolDetails() internal view returns ( address governance, address strategy, address indexFund, uint8 indexFundPercentage, uint8 swapPercentage ) { return unipilotFactory.getUnipilotDetails(); } function setPassivePositions( uint256 _amount0Desired, uint256 _amount1Desired ) internal returns (uint256 amount0, uint256 amount1) { Tick memory ticks; ( ticks.baseTickLower, ticks.baseTickUpper, ticks.bidTickLower, ticks.bidTickUpper, ticks.rangeTickLower, ticks.rangeTickUpper ) = _getTicksFromUniStrategy(address(pool)); (amount0, amount1) = pool.mintLiquidity( ticks.baseTickLower, ticks.baseTickUpper, _amount0Desired, _amount1Desired ); ticksData.baseTickLower = ticks.baseTickLower; ticksData.baseTickUpper = ticks.baseTickUpper; uint256 remainingAmount0 = _amount0Desired.sub(amount0); uint256 remainingAmount1 = _amount1Desired.sub(amount1); uint128 rangeLiquidity; if (remainingAmount0 > 0 || remainingAmount1 > 0) { uint128 range0 = pool.getLiquidityForAmounts( remainingAmount0, remainingAmount1, ticks.bidTickLower, ticks.bidTickUpper ); uint128 range1 = pool.getLiquidityForAmounts( remainingAmount0, remainingAmount1, ticks.rangeTickLower, ticks.rangeTickUpper ); /// @dev only one range position will ever have liquidity (if any) if (range1 < range0) { rangeLiquidity = range0; ticksData.rangeTickLower = ticks.bidTickLower; ticksData.rangeTickUpper = ticks.bidTickUpper; } else if (range0 < range1) { ticksData.rangeTickLower = ticks.rangeTickLower; ticksData.rangeTickUpper = ticks.rangeTickUpper; rangeLiquidity = range1; } } if (rangeLiquidity > 0) { (uint256 _rangeAmount0, uint256 _rangeAmount1) = pool.mintLiquidity( ticksData.rangeTickLower, ticksData.rangeTickUpper, remainingAmount0, remainingAmount1 ); amount0 = amount0.add(_rangeAmount0); amount1 = amount1.add(_rangeAmount1); } } /// @dev Burn all the liquidity of unipilot positions, collects up to a /// maximum amount of fees owed to position to the vault address & /// tranfer fees percentage to index fund. function burnAndCollect( int24 tickLower, int24 tickUpper, uint256 liquidityShare ) internal returns (uint256 burnt0, uint256 burnt1) { (burnt0, burnt1) = pool.burnUserLiquidity( tickLower, tickUpper, liquidityShare, address(this) ); (uint256 fees0, uint256 fees1) = pool.collectPendingFees( address(this), tickLower, tickUpper ); transferFeesToIF(false, fees0, fees1); } /// @dev fetches the new ticks for base and range positions function _getTicksFromUniStrategy(address _pool) internal returns ( int24 baseTickLower, int24 baseTickUpper, int24 bidTickLower, int24 bidTickUpper, int24 rangeTickLower, int24 rangeTickUpper ) { (, address strategy, , , ) = getProtocolDetails(); return IUnipilotStrategy(strategy).getTicks(_pool); } /// @dev method to transfer unipilot earned fees to Index Fund function transferFeesToIF( bool isReadjustLiquidity, uint256 fees0, uint256 fees1 ) internal { (, , address indexFund, uint8 percentage, ) = getProtocolDetails(); if (fees0 > 0) TransferHelper.safeTransfer( address(token0), indexFund, FullMath.mulDiv(fees0, percentage, 100) ); if (fees1 > 0) TransferHelper.safeTransfer( address(token1), indexFund, FullMath.mulDiv(fees1, percentage, 100) ); emit FeesSnapshot(isReadjustLiquidity, fees0, fees1); } function transferFunds( bool refundAsETH, address recipient, address token, uint256 amount ) internal { if (refundAsETH && token == WETH) { unwrapWETH9(amount, recipient); } else { TransferHelper.safeTransfer(token, recipient, amount); } } /// @param token The token to pay /// @param payer The entity that must pay /// @param recipient The entity that will receive payment /// @param value The amount to pay function pay( address token, address payer, address recipient, uint256 value ) internal { if (token == WETH && address(this).balance >= value) { // pay with WETH9 IWETH9(WETH).deposit{ value: value }(); // wrap only what is needed to pay IWETH9(WETH).transfer(recipient, value); } else if (payer == address(this)) { // pay with tokens already in the contract (for the exact input multihop case) TransferHelper.safeTransfer(token, recipient, value); } else { // pull payment TransferHelper.safeTransferFrom(token, payer, recipient, value); } } /// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH. /// @param balanceWETH9 The amount of WETH9 to unwrap /// @param recipient The address receiving ETH function unwrapWETH9(uint256 balanceWETH9, address recipient) internal { IWETH9(WETH).withdraw(balanceWETH9); TransferHelper.safeTransferETH(recipient, balanceWETH9); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.7.6; /// @title The interface for the Unipilot Factory interface IUnipilotFactory { /// @notice Emitted when a vault is created /// @param _tokenA The first token of the pool by address sort order /// @param _tokenB The second token of the pool by address sort order /// @param _vault The address of the vault that is created event VaultCreated( address indexed _tokenA, address indexed _tokenB, uint16 _strategyType, address indexed _vault ); /// @notice Emitted when the governance of the factory is changed /// @param _oldGovernance The governance before the governance was changed /// @param _newGovernance The governance after the governance was changed event GovernanceChanged( address indexed _oldGovernance, address indexed _newGovernance ); /// @notice Creates a vault for the given two tokens and fee /// @param _tokenA The first token of the pool by address sort order /// @param _tokenB The second token of the pool by address sort order /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. /// The call will revert if the vault already exists, the fee is invalid, or the token arguments /// are invalid. /// @return _vault The address of the newly created pool function createVault( address _tokenA, address _tokenB, uint16 _vaultStrategy, uint160 _sqrtPriceX96, string memory _name, string memory _symbol ) external returns (address _vault); /// @notice Used to give addresses of governance, strategy, indexFund /// @return governance address, strategy address, indexFund address function getUnipilotDetails() external view returns ( address, address, address, uint8, uint8 ); }
// 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); 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); 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 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: 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: GPL-2.0-or-later pragma solidity >=0.6.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; //import "../interfaces/external/IERC20.sol"; library TransferHelper { /// @notice Transfers tokens from the targeted address to the given destination /// @notice Errors with 'STF' if transfer fails /// @param token The contract address of the token to be transferred /// @param from The originating address from which the tokens will be transferred /// @param to The destination address of the transfer /// @param value The amount to be transferred function safeTransferFrom( address token, address from, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector( IERC20.transferFrom.selector, from, to, value ) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "STF" ); } /// @notice Transfers tokens from msg.sender to a recipient /// @dev Errors with ST if transfer fails /// @param token The contract address of the token which will be transferred /// @param to The recipient of the transfer /// @param value The value of the transfer function safeTransfer( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.transfer.selector, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "ST" ); } /// @notice Approves the stipulated contract to spend the given allowance in the given token /// @dev Errors with 'SA' if transfer fails /// @param token The contract address of the token to be approved /// @param to The target of the approval /// @param value The amount of the given token the target will be allowed to spend function safeApprove( address token, address to, uint256 value ) internal { (bool success, bytes memory data) = token.call( abi.encodeWithSelector(IERC20.approve.selector, to, value) ); require( success && (data.length == 0 || abi.decode(data, (bool))), "SA" ); } /// @notice Transfers ETH to the recipient address /// @dev Fails with `STE` /// @param to The destination of the transfer /// @param value The value to be transferred function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{ value: value }(new bytes(0)); require(success, "STE"); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity =0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title Interface for WETH9 interface IWETH9 is IERC20 { /// @notice Deposit ether to get wrapped ether function deposit() external payable; /// @notice Withdraw wrapped ether to get ether function withdraw(uint256) external; }
//SPDX-License-Identifier: MIT pragma solidity ^0.7.6; interface IUnipilotVault { struct ReadjustVars { uint256 fees0; uint256 fees1; int24 currentTick; int24 tickLower; int24 tickUpper; uint256 amount0Desired; uint256 amount1Desired; uint128 liquidity; uint256 amount0; uint256 amount1; bool zeroForOne; int256 amountSpecified; uint160 exactSqrtPriceImpact; uint160 sqrtPriceLimitX96; } struct TicksData { int24 baseTickLower; int24 baseTickUpper; int24 rangeTickLower; int24 rangeTickUpper; } struct Tick { int24 baseTickLower; int24 baseTickUpper; int24 bidTickLower; int24 bidTickUpper; int24 rangeTickLower; int24 rangeTickUpper; } struct Cache { uint256 totalSupply; uint256 liquidityShare; } event Deposit( address indexed depositor, address indexed recipient, uint256 amount0, uint256 amount1, uint256 lpShares ); event FeesSnapshot(bool isReadjustLiquidity, uint256 fees0, uint256 fees1); event Withdraw( address indexed recipient, uint256 shares, uint256 amount0, uint256 amount1 ); event PullLiquidity( uint256 reserves0, uint256 reserves1, uint256 fees0, uint256 fees1 ); event CompoundFees(uint256 amount0, uint256 amount1); /// @notice Deposits tokens in proportion to the Unipilot's current holdings & mints them /// `Unipilot`s LP token. /// @param amount0Desired Max amount of token0 to deposit /// @param amount1Desired Max amount of token1 to deposit /// @param recipient Recipient of shares /// @return lpShares Number of shares minted /// @return amount0 Amount of token0 deposited in vault /// @return amount1 Amount of token1 deposited in vault function deposit( uint256 amount0Desired, uint256 amount1Desired, address recipient ) external payable returns ( uint256 lpShares, uint256 amount0, uint256 amount1 ); /// @notice Withdraws the desired shares from the vault with accumulated user fees and transfers to recipient. /// @param recipient Recipient of tokens /// @param refundAsETH whether to recieve in WETH or ETH (only valid for WETH/ALT pairs) /// @return amount0 Amount of token0 sent to recipient /// @return amount1 Amount of token1 sent to recipient function withdraw( uint256 liquidity, address recipient, bool refundAsETH ) external returns (uint256 amount0, uint256 amount1); /// @notice Pull in tokens from sender. Called to `msg.sender` after minting liquidity to a position from IUniswapV3Pool#mint. /// @dev In the implementation you must pay to the pool for the minted liquidity. /// @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 IUniswapV3PoolActions#mint call function algebraMintCallback( uint256 amount0Owed, uint256 amount1Owed, bytes calldata data ) external; /// @notice Called to `msg.sender` after minting swaping from IUniswapV3Pool#swap. /// @dev In the implementation you must pay to the pool for swap. /// @param amount0Delta The amount of token0 due to the pool for the swap /// @param amount1Delta The amount of token1 due to the pool for the swap /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call function algebraSwapCallback( int256 amount0Delta, int256 amount1Delta, bytes calldata data ) external; /// @notice Burns all position(s), collects any fees accrued and updates Unipilot's position(s) /// @dev mints all amounts to this position(s) (including earned fees) /// @dev For active vaults it can be called by the governance or operator, /// swaps imbalanced token and add all liquidity in base position. /// @dev For passive vaults it can be called by any user. /// Two positions are placed - a base position and a limit position. The base /// position is placed first with as much liquidity as possible. This position /// should use up all of one token, leaving only the other one. This excess /// amount is then placed as a single-sided bid or ask position. function readjustLiquidity(uint8 swapBP) external; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.7.6; pragma abicoder v2; interface IUnipilotStrategy { struct PoolStrategy { int24 baseThreshold; int24 rangeThreshold; int24 maxTwapDeviation; int24 readjustThreshold; uint32 twapDuration; int24 baseMultiplier; } event GovernanceUpdated(address oldGovernance, address newGovernance); event StrategyUpdated(PoolStrategy oldStrategy, PoolStrategy newStrategy); event MaxTwapDeviationUpdated(int24 oldDeviation, int24 newDeviation); event BaseTicksUpdated(int24 oldBaseTicks, int24 newBaseTicks); event RangeTicksUpdated(int24 oldRangeTicks, int24 newRangeTicks); event TwapDurationUpdated(uint32 oldDuration, uint32 newDuration); event ReadjustMultiplierUpdated(int24 oldMultiplier, int24 newMultiplier); function getTicks(address _pool) external returns ( int24 baseLower, int24 baseUpper, int24 bidLower, int24 bidUpper, int24 askLower, int24 askUpper ); function getTwap(address _pool) external view returns (int24); function getStrategy(address _pool) external view returns (PoolStrategy memory strategy); function getBaseThreshold(address _pool, uint16 _strategyType) external view returns (int24 baseThreshold); function twapDuration() external view returns (uint32); function maxTwapDeviation() external view returns (int24); function checkDeviation(address pool) external view; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import "./UniswapPoolActions.sol"; import "../interfaces/IUnipilotVault.sol"; import "@uniswap/v3-core/contracts/libraries/TickMath.sol"; import "@uniswap/v3-periphery/contracts/libraries/PositionKey.sol"; import "@cryptoalgebra/periphery/contracts/libraries/LiquidityAmounts.sol"; import "@cryptoalgebra/core/contracts/libraries/PriceMovementMath.sol"; /// @title Liquidity and ticks functions /// @notice Provides functions for computing liquidity and ticks for token amounts and prices library UniswapLiquidityManagement { using LowGasSafeMath for uint256; struct Info { uint256 amount0Desired; uint256 amount1Desired; uint256 amount0; uint256 amount1; uint128 liquidity; int24 tickLower; int24 tickUpper; } /// @dev Wrapper around `LiquidityAmounts.getAmountsForLiquidity()`. /// @param pool Uniswap V3 pool /// @param liquidity The liquidity being valued /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return amounts of token0 and token1 that corresponds to liquidity function getAmountsForLiquidity( IAlgebraPool pool, uint128 liquidity, int24 _tickLower, int24 _tickUpper ) internal view returns (uint256, uint256) { (uint160 sqrtRatioX96, , , , , , ) = pool.globalState(); return LiquidityAmounts.getAmountsForLiquidity( sqrtRatioX96, TickMath.getSqrtRatioAtTick(_tickLower), TickMath.getSqrtRatioAtTick(_tickUpper), liquidity ); } /// @dev Wrapper around `LiquidityAmounts.getLiquidityForAmounts()`. /// @param pool Uniswap V3 pool /// @param amount0 The amount of token0 /// @param amount1 The amount of token1 /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return The maximum amount of liquidity that can be held amount0 and amount1 function getLiquidityForAmounts( IAlgebraPool pool, uint256 amount0, uint256 amount1, int24 _tickLower, int24 _tickUpper ) internal view returns (uint128) { (uint160 sqrtRatioX96, , , , , , ) = pool.globalState(); return LiquidityAmounts.getLiquidityForAmounts( sqrtRatioX96, TickMath.getSqrtRatioAtTick(_tickLower), TickMath.getSqrtRatioAtTick(_tickUpper), amount0, amount1 ); } /// @dev Amount of liquidity in contract position. /// @param pool Uniswap V3 pool /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return liquidity stored in position function getPositionLiquidity( IAlgebraPool pool, int24 _tickLower, int24 _tickUpper ) internal view returns ( uint128 liquidity, uint128 tokensOwed0, uint128 tokensOwed1 ) { bytes32 positionKey; address vault = address(this); assembly { positionKey := or( shl(24, or(shl(24, vault), and(_tickLower, 0xFFFFFF))), and(_tickUpper, 0xFFFFFF) ) } (liquidity, , , , tokensOwed0, tokensOwed1) = pool.positions( positionKey ); } /// @dev Rounds tick down towards negative infinity so that it's a multiple /// of `tickSpacing`. function floor(int24 tick, int24 tickSpacing) internal pure returns (int24) { int24 compressed = tick / tickSpacing; if (tick < 0 && tick % tickSpacing != 0) compressed--; return compressed * tickSpacing; } function getSqrtRatioX96AndTick(IAlgebraPool pool) internal view returns ( uint160 _sqrtRatioX96, int24 _tick, uint16 observationCardinality ) { (_sqrtRatioX96, _tick, , observationCardinality, , , ) = pool .globalState(); } /// @dev Calc base ticks depending on base threshold and tickspacing function getBaseTicks( int24 currentTick, int24 baseThreshold, int24 tickSpacing ) internal pure returns (int24 tickLower, int24 tickUpper) { int24 tickFloor = floor(currentTick, tickSpacing); tickLower = tickFloor - baseThreshold; tickUpper = tickFloor + baseThreshold; } function collectableAmountsInPosition( IAlgebraPool pool, int24 _lowerTick, int24 _upperTick ) internal view returns ( uint256, uint256, uint256, uint256 ) { ( uint128 liquidity, uint128 earnable0, uint128 earnable1 ) = getPositionLiquidity(pool, _lowerTick, _upperTick); (uint256 burnable0, uint256 burnable1) = UniswapLiquidityManagement .getAmountsForLiquidity(pool, liquidity, _lowerTick, _upperTick); return (burnable0, burnable1, earnable0, earnable1); } function computeLpShares( IAlgebraPool pool, bool isWhitelisted, uint256 amount0Max, uint256 amount1Max, uint256 balance0, uint256 balance1, uint256 totalSupply, IUnipilotVault.TicksData memory ticks ) internal returns ( uint256 shares, uint256 amount0, uint256 amount1 ) { ( uint256 res0, uint256 res1, uint256 fees0, uint256 fees1, , ) = getTotalAmounts(pool, isWhitelisted, ticks); uint256 reserve0 = res0.add(fees0).add(balance0); uint256 reserve1 = res1.add(fees1).add(balance1); // If total supply > 0, pool can't be empty assert(totalSupply == 0 || reserve0 != 0 || reserve1 != 0); (shares, amount0, amount1) = calculateShare( amount0Max, amount1Max, reserve0, reserve1, totalSupply ); } function getTotalAmounts( IAlgebraPool pool, bool isWhitelisted, IUnipilotVault.TicksData memory ticks ) internal returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1, uint128 baseLiquidity, uint128 rangeLiquidity ) { (amount0, amount1, fees0, fees1, baseLiquidity) = getReserves( pool, ticks.baseTickLower, ticks.baseTickUpper ); if (!isWhitelisted) { ( uint256 range0, uint256 range1, uint256 rangeFees0, uint256 rangeFees1, uint128 rangeliquidity ) = getReserves(pool, ticks.rangeTickLower, ticks.rangeTickUpper); amount0 = amount0.add(range0); amount1 = amount1.add(range1); fees0 = fees0.add(rangeFees0); fees1 = fees1.add(rangeFees1); rangeLiquidity = rangeliquidity; } } function getReserves( IAlgebraPool pool, int24 tickLower, int24 tickUpper ) internal returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1, uint128 liquidity ) { liquidity = UniswapPoolActions.updatePosition( pool, tickLower, tickUpper ); if (liquidity > 0) { (amount0, amount1, fees0, fees1) = collectableAmountsInPosition( pool, tickLower, tickUpper ); } } function calculateShare( uint256 amount0Max, uint256 amount1Max, uint256 reserve0, uint256 reserve1, uint256 totalSupply ) internal pure returns ( uint256 shares, uint256 amount0, uint256 amount1 ) { if (totalSupply == 0) { // For first deposit, just use the amounts desired amount0 = amount0Max; amount1 = amount1Max; shares = amount0 > amount1 ? amount0 : amount1; // max } else if (reserve0 == 0) { amount1 = amount1Max; shares = FullMath.mulDiv(amount1, totalSupply, reserve1); } else if (reserve1 == 0) { amount0 = amount0Max; shares = FullMath.mulDiv(amount0, totalSupply, reserve0); } else { amount0 = FullMath.mulDiv(amount1Max, reserve0, reserve1); if (amount0 < amount0Max) { amount1 = amount1Max; shares = FullMath.mulDiv(amount1, totalSupply, reserve1); } else { amount0 = amount0Max; amount1 = FullMath.mulDiv(amount0, reserve1, reserve0); shares = FullMath.mulDiv(amount0, totalSupply, reserve0); } } } /// @dev Gets ticks with proportion equivalent to desired amount /// @param pool Uniswap V3 pool /// @param amount0Desired The desired amount of token0 /// @param amount1Desired The desired amount of token1 /// @param baseThreshold The range for upper and lower ticks /// @param tickSpacing The pool tick spacing /// @return tickLower The lower tick of the range /// @return tickUpper The upper tick of the range function getPositionTicks( IAlgebraPool pool, uint256 amount0Desired, uint256 amount1Desired, int24 baseThreshold, int24 tickSpacing ) internal view returns (int24 tickLower, int24 tickUpper) { Info memory cache = Info(amount0Desired, amount1Desired, 0, 0, 0, 0, 0); // Get current price and tick from the pool (uint160 sqrtPriceX96, int24 currentTick, , , , , ) = pool .globalState(); //Calc base ticks (cache.tickLower, cache.tickUpper) = getBaseTicks( currentTick, baseThreshold, tickSpacing ); //Calc amounts of token0 and token1 that can be stored in base range (cache.amount0, cache.amount1) = getAmountsForTicks( pool, cache.amount0Desired, cache.amount1Desired, cache.tickLower, cache.tickUpper ); // //Liquidity that can be stored in base range cache.liquidity = getLiquidityForAmounts( pool, cache.amount0, cache.amount1, cache.tickLower, cache.tickUpper ); // //Get imbalanced token bool zeroGreaterOne = amountsDirection( cache.amount0Desired, cache.amount1Desired, cache.amount0, cache.amount1 ); //Calc new tick(upper or lower) for imbalanced token if (zeroGreaterOne) { uint160 nextSqrtPrice0 = PriceMovementMath.getNewPrice( sqrtPriceX96, cache.liquidity, cache.amount0Desired, false, false ); cache.tickUpper = floor( TickMath.getTickAtSqrtRatio(nextSqrtPrice0), tickSpacing ); } else { uint160 nextSqrtPrice1 = PriceMovementMath.getNewPrice( sqrtPriceX96, cache.liquidity, cache.amount1Desired, true, false ); cache.tickLower = floor( TickMath.getTickAtSqrtRatio(nextSqrtPrice1), tickSpacing ); } checkRange(cache.tickLower, cache.tickUpper, tickSpacing); /// floor the tick again because one tick is still not valid tick due to + - baseThreshold tickLower = floor(cache.tickLower, tickSpacing); tickUpper = floor(cache.tickUpper, tickSpacing); } /// @dev Gets amounts of token0 and token1 that can be stored in range of upper and lower ticks /// @param pool Uniswap V3 pool /// @param amount0Desired The desired amount of token0 /// @param amount1Desired The desired amount of token1 /// @param _tickLower The lower tick of the range /// @param _tickUpper The upper tick of the range /// @return amount0 amounts of token0 that can be stored in range /// @return amount1 amounts of token1 that can be stored in range function getAmountsForTicks( IAlgebraPool pool, uint256 amount0Desired, uint256 amount1Desired, int24 _tickLower, int24 _tickUpper ) internal view returns (uint256 amount0, uint256 amount1) { uint128 liquidity = getLiquidityForAmounts( pool, amount0Desired, amount1Desired, _tickLower, _tickUpper ); (amount0, amount1) = getAmountsForLiquidity( pool, liquidity, _tickLower, _tickUpper ); } /// @dev Common checks for valid tick inputs. /// @param tickLower The lower tick of the range /// @param tickUpper The upper tick of the range /// @param tickSpacing The pool tick spacing function checkRange( int24 tickLower, int24 tickUpper, int24 tickSpacing ) internal pure { require(tickLower < tickUpper, "TLU"); require(tickLower >= TickMath.MIN_TICK, "TLM"); require(tickUpper <= TickMath.MAX_TICK, "TUM"); require(tickLower % tickSpacing == 0, "TLI"); require(tickUpper % tickSpacing == 0, "TUI"); } /// @dev Get imbalanced token /// @param amount0Desired The desired amount of token0 /// @param amount1Desired The desired amount of token1 /// @param amount0 Amounts of token0 that can be stored in base range /// @param amount1 Amounts of token1 that can be stored in base range /// @return zeroGreaterOne true if token0 is imbalanced. False if token1 is imbalanced function amountsDirection( uint256 amount0Desired, uint256 amount1Desired, uint256 amount0, uint256 amount1 ) internal pure returns (bool zeroGreaterOne) { zeroGreaterOne = amount0Desired.sub(amount0).mul(amount1Desired) > amount1Desired.sub(amount1).mul(amount0Desired) ? true : false; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such 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. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCastExtended { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2**128, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { require(value < 2**64, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { require(value < 2**32, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { require(value < 2**16, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8) { require(value < 2**8, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128) { require( value >= -2**127 && value < 2**127, "SafeCast: value doesn't fit in 128 bits" ); return int128(value); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64) { require( value >= -2**63 && value < 2**63, "SafeCast: value doesn't fit in 64 bits" ); return int64(value); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32) { require( value >= -2**31 && value < 2**31, "SafeCast: value doesn't fit in 32 bits" ); return int32(value); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16) { require( value >= -2**15 && value < 2**15, "SafeCast: value doesn't fit in 16 bits" ); return int16(value); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits. * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8) { require( value >= -2**7 && value < 2**7, "SafeCast: value doesn't fit in 8 bits" ); return int8(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require(value < 2**255, "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import "./SafeCastExtended.sol"; import "./UniswapLiquidityManagement.sol"; import "@cryptoalgebra/core/contracts/libraries/FullMath.sol"; import "@cryptoalgebra/core/contracts/interfaces/IAlgebraPool.sol"; import "@cryptoalgebra/core/contracts/libraries/LowGasSafeMath.sol"; /// @title Liquidity and ticks functions /// @notice Provides functions for computing liquidity and ticks for token amounts and prices library UniswapPoolActions { using LowGasSafeMath for uint256; using SafeCastExtended for uint256; using UniswapLiquidityManagement for IAlgebraPool; function updatePosition( IAlgebraPool pool, int24 tickLower, int24 tickUpper ) internal returns (uint128 liquidity) { (liquidity, , ) = pool.getPositionLiquidity(tickLower, tickUpper); if (liquidity > 0) { pool.burn(tickLower, tickUpper, 0); } } function burnLiquidity( IAlgebraPool pool, int24 tickLower, int24 tickUpper, address recipient ) internal returns ( uint256 amount0, uint256 amount1, uint256 fees0, uint256 fees1 ) { (uint128 liquidity, , ) = pool.getPositionLiquidity( tickLower, tickUpper ); if (liquidity > 0) { (amount0, amount1) = pool.burn(tickLower, tickUpper, liquidity); if (amount0 > 0 || amount1 > 0) { (uint256 collect0, uint256 collect1) = pool.collect( recipient, tickLower, tickUpper, type(uint128).max, type(uint128).max ); (fees0, fees1) = (collect0.sub(amount0), collect1.sub(amount1)); } } } function burnUserLiquidity( IAlgebraPool pool, int24 tickLower, int24 tickUpper, uint256 userSharePercentage, address recipient ) internal returns (uint256 amount0, uint256 amount1) { (uint128 liquidity, , ) = pool.getPositionLiquidity( tickLower, tickUpper ); uint256 liquidityRemoved = FullMath.mulDiv( uint256(liquidity), userSharePercentage, 1e18 ); (amount0, amount1) = pool.burn( tickLower, tickUpper, liquidityRemoved.toUint128() ); if (amount0 > 0 || amount1 > 0) { (amount0, amount0) = pool.collect( recipient, tickLower, tickUpper, amount0.toUint128(), amount1.toUint128() ); } } function mintLiquidity( IAlgebraPool pool, int24 tickLower, int24 tickUpper, uint256 amount0Desired, uint256 amount1Desired ) internal returns (uint256 amount0, uint256 amount1) { uint128 liquidity = pool.getLiquidityForAmounts( amount0Desired, amount1Desired, tickLower, tickUpper ); if (liquidity > 0) { (amount0, amount1, ) = pool.mint( address(this), address(this), tickLower, tickUpper, liquidity, abi.encode(address(this)) ); } } function swapToken( IAlgebraPool pool, address recipient, bool zeroForOne, int256 amountSpecified ) internal { (uint160 sqrtPriceX96, , ) = pool.getSqrtRatioX96AndTick(); uint160 exactSqrtPriceImpact = (sqrtPriceX96 * (1e5 / 2)) / 1e6; uint160 sqrtPriceLimitX96 = zeroForOne ? sqrtPriceX96 - exactSqrtPriceImpact : sqrtPriceX96 + exactSqrtPriceImpact; pool.swap( recipient, zeroForOne, amountSpecified, sqrtPriceLimitX96, abi.encode(zeroForOne) ); } function collectPendingFees( IAlgebraPool pool, address recipient, int24 tickLower, int24 tickUpper ) internal returns (uint256 collect0, uint256 collect1) { updatePosition(pool, tickLower, tickUpper); (collect0, collect1) = pool.collect( recipient, tickLower, tickUpper, type(uint128).max, type(uint128).max ); } function rerangeLiquidity( IAlgebraPool pool, int24 baseThreshold, int24 tickSpacing, uint256 balance0, uint256 balance1 ) internal returns (int24 tickLower, int24 tickUpper) { (tickLower, tickUpper) = pool.getPositionTicks( balance0, balance1, baseThreshold, tickSpacing ); mintLiquidity(pool, tickLower, tickUpper, balance0, balance1); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.5 <0.8.0; import "../token/ERC20/ERC20.sol"; import "./IERC20Permit.sol"; import "../cryptography/ECDSA.sol"; import "../utils/Counters.sol"; import "./EIP712.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping (address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private immutable _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") { } /** * @dev See {IERC20Permit-permit}. */ function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public virtual override { // solhint-disable-next-line not-rely-on-time require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode( _PERMIT_TYPEHASH, owner, spender, value, _nonces[owner].current(), deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _nonces[owner].increment(); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } }
// 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: 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 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 sqrtPriceX96 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 sqrtPriceX96) { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); 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 sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 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 sqrtPriceX96) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R'); uint256 ratio = uint256(sqrtPriceX96) << 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) <= sqrtPriceX96 ? tickHi : tickLow; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; library PositionKey { /// @dev Returns the key of the position in the core library function compute( address owner, int24 tickLower, int24 tickUpper ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(owner, tickLower, tickUpper)); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '@cryptoalgebra/core/contracts/libraries/FullMath.sol'; import '@cryptoalgebra/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: BUSL-1.1 pragma solidity =0.7.6; import './FullMath.sol'; import './TokenDeltaMath.sol'; /// @title Computes the result of price movement /// @notice Contains methods for computing the result of price movement within a single tick price range. library PriceMovementMath { using LowGasSafeMath for uint256; using SafeCast for uint256; /// @notice Gets the next sqrt price given an input amount of token0 or token1 /// @dev Throws if price or liquidity are 0, or if the next price is out of bounds /// @param price The starting Q64.96 sqrt price, i.e., before accounting for the input amount /// @param liquidity The amount of usable liquidity /// @param input How much of token0, or token1, is being swapped in /// @param zeroToOne Whether the amount in is token0 or token1 /// @return resultPrice The Q64.96 sqrt price after adding the input amount to token0 or token1 function getNewPriceAfterInput( uint160 price, uint128 liquidity, uint256 input, bool zeroToOne ) internal pure returns (uint160 resultPrice) { return getNewPrice(price, liquidity, input, zeroToOne, true); } /// @notice Gets the next sqrt price given an output amount of token0 or token1 /// @dev Throws if price or liquidity are 0 or the next price is out of bounds /// @param price The starting Q64.96 sqrt price before accounting for the output amount /// @param liquidity The amount of usable liquidity /// @param output How much of token0, or token1, is being swapped out /// @param zeroToOne Whether the amount out is token0 or token1 /// @return resultPrice The Q64.96 sqrt price after removing the output amount of token0 or token1 function getNewPriceAfterOutput( uint160 price, uint128 liquidity, uint256 output, bool zeroToOne ) internal pure returns (uint160 resultPrice) { return getNewPrice(price, liquidity, output, zeroToOne, false); } function getNewPrice( uint160 price, uint128 liquidity, uint256 amount, bool zeroToOne, bool fromInput ) internal pure returns (uint160 resultPrice) { require(price > 0); require(liquidity > 0); if (zeroToOne == fromInput) { // rounding up or down if (amount == 0) return price; uint256 liquidityShifted = uint256(liquidity) << Constants.RESOLUTION; if (fromInput) { uint256 product; if ((product = amount * price) / amount == price) { uint256 denominator = liquidityShifted + product; if (denominator >= liquidityShifted) return uint160(FullMath.mulDivRoundingUp(liquidityShifted, price, denominator)); // always fits in 160 bits } return uint160(FullMath.divRoundingUp(liquidityShifted, (liquidityShifted / price).add(amount))); } else { uint256 product; require((product = amount * price) / amount == price); // if the product overflows, we know the denominator underflows require(liquidityShifted > product); // in addition, we must check that the denominator does not underflow return FullMath.mulDivRoundingUp(liquidityShifted, price, liquidityShifted - product).toUint160(); } } else { // if we're adding (subtracting), rounding down requires rounding the quotient down (up) // in both cases, avoid a mulDiv for most inputs if (fromInput) { return uint256(price) .add(amount <= type(uint160).max ? (amount << Constants.RESOLUTION) / liquidity : FullMath.mulDiv(amount, Constants.Q96, liquidity)) .toUint160(); } else { uint256 quotient = amount <= type(uint160).max ? FullMath.divRoundingUp(amount << Constants.RESOLUTION, liquidity) : FullMath.mulDivRoundingUp(amount, Constants.Q96, liquidity); require(price > quotient); return uint160(price - quotient); // always fits 160 bits } } } function getTokenADelta01( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken0Delta(to, from, liquidity, true); } function getTokenADelta10( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken1Delta(from, to, liquidity, true); } function getTokenBDelta01( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken1Delta(to, from, liquidity, false); } function getTokenBDelta10( uint160 to, uint160 from, uint128 liquidity ) internal pure returns (uint256) { return TokenDeltaMath.getToken0Delta(from, to, liquidity, false); } /// @notice Computes the result of swapping some amount in, or amount out, given the parameters of the swap /// @dev The fee, plus the amount in, will never exceed the amount remaining if the swap's `amountSpecified` is positive /// @param currentPrice The current Q64.96 sqrt price of the pool /// @param targetPrice The Q64.96 sqrt price that cannot be exceeded, from which the direction of the swap is inferred /// @param liquidity The usable liquidity /// @param amountAvailable How much input or output amount is remaining to be swapped in/out /// @param fee The fee taken from the input amount, expressed in hundredths of a bip /// @return resultPrice The Q64.96 sqrt price after swapping the amount in/out, not to exceed the price target /// @return input The amount to be swapped in, of either token0 or token1, based on the direction of the swap /// @return output The amount to be received, of either token0 or token1, based on the direction of the swap /// @return feeAmount The amount of input that will be taken as a fee function movePriceTowardsTarget( bool zeroToOne, uint160 currentPrice, uint160 targetPrice, uint128 liquidity, int256 amountAvailable, uint16 fee ) internal pure returns ( uint160 resultPrice, uint256 input, uint256 output, uint256 feeAmount ) { function(uint160, uint160, uint128) pure returns (uint256) getAmountA = zeroToOne ? getTokenADelta01 : getTokenADelta10; if (amountAvailable >= 0) { // exactIn or not uint256 amountAvailableAfterFee = FullMath.mulDiv(uint256(amountAvailable), 1e6 - fee, 1e6); input = getAmountA(targetPrice, currentPrice, liquidity); if (amountAvailableAfterFee >= input) { resultPrice = targetPrice; feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } else { resultPrice = getNewPriceAfterInput(currentPrice, liquidity, amountAvailableAfterFee, zeroToOne); if (targetPrice != resultPrice) { input = getAmountA(resultPrice, currentPrice, liquidity); // we didn't reach the target, so take the remainder of the maximum input as fee feeAmount = uint256(amountAvailable) - input; } else { feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } } output = (zeroToOne ? getTokenBDelta01 : getTokenBDelta10)(resultPrice, currentPrice, liquidity); } else { function(uint160, uint160, uint128) pure returns (uint256) getAmountB = zeroToOne ? getTokenBDelta01 : getTokenBDelta10; output = getAmountB(targetPrice, currentPrice, liquidity); amountAvailable = -amountAvailable; if (uint256(amountAvailable) >= output) resultPrice = targetPrice; else { resultPrice = getNewPriceAfterOutput(currentPrice, liquidity, uint256(amountAvailable), zeroToOne); if (targetPrice != resultPrice) { output = getAmountB(resultPrice, currentPrice, liquidity); } // cap the output amount to not exceed the remaining output amount if (output > uint256(amountAvailable)) { output = uint256(amountAvailable); } } input = getAmountA(resultPrice, currentPrice, liquidity); feeAmount = FullMath.mulDivRoundingUp(input, fee, 1e6 - fee); } } }
// 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.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 TICK_SPACING = 60; // max(uint128) / ( (MAX_TICK - MIN_TICK) / TICK_SPACING ) uint128 internal constant MAX_LIQUIDITY_PER_TICK = 11505743598341114571880798222544994; 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: BUSL-1.1 pragma solidity =0.7.6; import './LowGasSafeMath.sol'; import './SafeCast.sol'; import './FullMath.sol'; import './Constants.sol'; /// @title Functions based on Q64.96 sqrt price and liquidity /// @notice Contains the math that uses square root of price as a Q64.96 and liquidity to compute deltas library TokenDeltaMath { using LowGasSafeMath for uint256; using SafeCast for uint256; /// @notice Gets the token0 delta between two prices /// @dev Calculates liquidity / sqrt(lower) - liquidity / sqrt(upper) /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up or down /// @return token0Delta Amount of token0 required to cover a position of size liquidity between the two passed prices function getToken0Delta( uint160 priceLower, uint160 priceUpper, uint128 liquidity, bool roundUp ) internal pure returns (uint256 token0Delta) { uint256 priceDelta = priceUpper - priceLower; require(priceDelta < priceUpper); // forbids underflow and 0 priceLower uint256 liquidityShifted = uint256(liquidity) << Constants.RESOLUTION; token0Delta = roundUp ? FullMath.divRoundingUp(FullMath.mulDivRoundingUp(priceDelta, liquidityShifted, priceUpper), priceLower) : FullMath.mulDiv(priceDelta, liquidityShifted, priceUpper) / priceLower; } /// @notice Gets the token1 delta between two prices /// @dev Calculates liquidity * (sqrt(upper) - sqrt(lower)) /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The amount of usable liquidity /// @param roundUp Whether to round the amount up, or down /// @return token1Delta Amount of token1 required to cover a position of size liquidity between the two passed prices function getToken1Delta( uint160 priceLower, uint160 priceUpper, uint128 liquidity, bool roundUp ) internal pure returns (uint256 token1Delta) { require(priceUpper >= priceLower); uint256 priceDelta = priceUpper - priceLower; token1Delta = roundUp ? FullMath.mulDivRoundingUp(priceDelta, liquidity, Constants.Q96) : FullMath.mulDiv(priceDelta, liquidity, Constants.Q96); } /// @notice Helper that gets signed token0 delta /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The change in liquidity for which to compute the token0 delta /// @return token0Delta Amount of token0 corresponding to the passed liquidityDelta between the two prices function getToken0Delta( uint160 priceLower, uint160 priceUpper, int128 liquidity ) internal pure returns (int256 token0Delta) { token0Delta = liquidity >= 0 ? getToken0Delta(priceLower, priceUpper, uint128(liquidity), true).toInt256() : -getToken0Delta(priceLower, priceUpper, uint128(-liquidity), false).toInt256(); } /// @notice Helper that gets signed token1 delta /// @param priceLower A Q64.96 sqrt price /// @param priceUpper Another Q64.96 sqrt price /// @param liquidity The change in liquidity for which to compute the token1 delta /// @return token1Delta Amount of token1 corresponding to the passed liquidityDelta between the two prices function getToken1Delta( uint160 priceLower, uint160 priceUpper, int128 liquidity ) internal pure returns (int256 token1Delta) { token1Delta = liquidity >= 0 ? getToken1Delta(priceLower, priceUpper, uint128(liquidity), true).toInt256() : -getToken1Delta(priceLower, priceUpper, uint128(-liquidity), false).toInt256(); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Safe casting methods /// @notice Contains methods for safely casting between types /// @dev Credit to Uniswap Labs under GPL-2.0-or-later license: /// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries library SafeCast { /// @notice Cast a uint256 to a uint160, revert on overflow /// @param y The uint256 to be downcasted /// @return z The downcasted integer, now type uint160 function toUint160(uint256 y) internal pure returns (uint160 z) { require((z = uint160(y)) == y); } /// @notice Cast a int256 to a int128, revert on overflow or underflow /// @param y The int256 to be downcasted /// @return z The downcasted integer, now type int128 function toInt128(int256 y) internal pure returns (int128 z) { require((z = int128(y)) == y); } /// @notice Cast a uint256 to a int256, revert on overflow /// @param y The uint256 to be casted /// @return z The casted integer, now type int256 function toInt256(uint256 y) internal pure returns (int256 z) { require(y < 2**255); z = int256(y); } }
// 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 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); /** * @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 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); }
// 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 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 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 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 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 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; 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: observe(). 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: 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: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens, * given `owner`'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length if (signature.length != 65) { revert("ECDSA: invalid signature length"); } // Divide the signature in r, s and v variables bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. // solhint-disable-next-line no-inline-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value"); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * replicates the behavior of the * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`] * JSON-RPC method. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; import "../math/SafeMath.sol"; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the {SafeMath} * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { // The {SafeMath} overflow check can be skipped here, see the comment at the top counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712 { /* solhint-disable var-name-mixedcase */ // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID; bytes32 private immutable _HASHED_NAME; bytes32 private immutable _HASHED_VERSION; bytes32 private immutable _TYPE_HASH; /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; _CACHED_CHAIN_ID = _getChainId(); _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion); _TYPE_HASH = typeHash; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view virtual returns (bytes32) { if (_getChainId() == _CACHED_CHAIN_ID) { return _CACHED_DOMAIN_SEPARATOR; } else { return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION); } } function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) { return keccak256( abi.encode( typeHash, name, version, _getChainId(), address(this) ) ); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash)); } function _getChainId() private view returns (uint256 chainId) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 // solhint-disable-next-line no-inline-assembly assembly { chainId := chainid() } } }
// 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 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; } }
{ "metadata": { "bytecodeHash": "none" }, "optimizer": { "enabled": true, "runs": 10 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"_algebraFactory","type":"address"},{"internalType":"address","name":"_governance","type":"address"},{"internalType":"address","name":"_uniStrategy","type":"address"},{"internalType":"address","name":"_indexFund","type":"address"},{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"uint8","name":"_indexFundPercentage","type":"uint8"},{"internalType":"uint8","name":"_swapPercentage","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"_newGovernance","type":"address"}],"name":"GovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_tokenA","type":"address"},{"indexed":true,"internalType":"address","name":"_tokenB","type":"address"},{"indexed":false,"internalType":"uint16","name":"_strategyType","type":"uint16"},{"indexed":true,"internalType":"address","name":"_vault","type":"address"}],"name":"VaultCreated","type":"event"},{"inputs":[{"internalType":"address","name":"_tokenA","type":"address"},{"internalType":"address","name":"_tokenB","type":"address"},{"internalType":"uint16","name":"_vaultStrategy","type":"uint16"},{"internalType":"uint160","name":"_sqrtPriceX96","type":"uint160"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"createVault","outputs":[{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getUnipilotDetails","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernance","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address","name":"_indexFund","type":"address"},{"internalType":"uint8","name":"_swapPercentage","type":"uint8"},{"internalType":"uint8","name":"_indexFundPercentage","type":"uint8"}],"name":"setUnipilotDetails","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint16","name":"","type":"uint16"}],"name":"vaults","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50604051615c75380380615c75833981810160405260e081101561003357600080fd5b508051602082015160408301516060840151608085015160a086015160c090960151600180546001600160a01b03199081166001600160a01b0397881617909155600280548216958716959095179094556004805485169686169690961790955560038054600080548616938716939093178355909316939091169290921760ff60a81b1916600160a81b60ff958616021760ff60a01b1916600160a01b949093169390930291909117909155615b859081906100f090396000f3fe60806040523480156200001157600080fd5b50600436106200005e5760003560e01c806338d772801462000063578063666bd3ab14620000ad578063ab033ea91462000107578063ca2f30821462000132578063d7dd98ea1462000176575b600080fd5b6200006d620002d2565b604080516001600160a01b0396871681529486166020860152929094168383015260ff908116606084015292909216608082015290519081900360a00190f35b620000eb60048036036060811015620000c557600080fd5b5080356001600160a01b03908116916020810135909116906040013561ffff1662000305565b604080516001600160a01b039092168252519081900360200190f35b62000130600480360360208110156200011f57600080fd5b50356001600160a01b031662000331565b005b62000130600480360360808110156200014a57600080fd5b506001600160a01b03813581169160208101359091169060ff60408201358116916060013516620003b9565b620000eb600480360360c08110156200018e57600080fd5b6001600160a01b038235811692602081013582169261ffff60408301351692606083013516919081019060a081016080820135600160201b811115620001d357600080fd5b820183602082011115620001e657600080fd5b803590602001918460018302840111600160201b831117156200020857600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156200025b57600080fd5b8201836020820111156200026e57600080fd5b803590602001918460018302840111600160201b831117156200029057600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955062000495945050505050565b6001546002546003546001600160a01b03928316939183169281169160ff600160a81b8304811692600160a01b90041690565b60056020908152600093845260408085208252928452828420905282529020546001600160a01b031681565b6001546001600160a01b031633146200034957600080fd5b6001600160a01b0381166200035d57600080fd5b6001546040516001600160a01b038084169216907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b03163314620003d157600080fd5b6001600160a01b03841615801590620003f257506001600160a01b03831615155b620003fc57600080fd5b60008260ff1611801562000413575060648260ff16105b6200041d57600080fd5b60008160ff1611801562000434575060648160ff16105b6200043e57600080fd5b600280546001600160a01b03199081166001600160a01b039687161790915560038054909116939094169290921760ff60a81b1916600160a81b60ff938416021760ff60a01b1916600160a01b9190921602179055565b6000856001600160a01b0316876001600160a01b03161415620004b757600080fd5b600080876001600160a01b0316896001600160a01b031610620004dc578789620004df565b88885b600480546040805163d9a641e160e01b81526001600160a01b03808716948201949094528385166024820152905194965092945060009391169163d9a641e1916044808301926020929190829003018186803b1580156200053f57600080fd5b505afa15801562000554573d6000803e3d6000fd5b505050506040513d60208110156200056b57600080fd5b505190506001600160a01b03811615620005c0576001600160a01b038381166000908152600560209081526040808320868516845282528083208380529091529020541615620005ba57600080fd5b620006b3565b600480546040805163e343361560e01b81526001600160a01b038781169482019490945285841660248201529051929091169163e3433615916044808201926020929091908290030181600087803b1580156200061c57600080fd5b505af115801562000631573d6000803e3d6000fd5b505050506040513d60208110156200064857600080fd5b50516040805163f637731d60e01b81526001600160a01b038a8116600483015291519293509083169163f637731d9160248082019260009290919082900301818387803b1580156200069957600080fd5b505af1158015620006ae573d6000803e3d6000fd5b505050505b60008390506000839050816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015620006f757600080fd5b505afa1580156200070c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156200073657600080fd5b8101908080516040519392919084600160201b8211156200075657600080fd5b9083019060208201858111156200076c57600080fd5b8251600160201b8111828201881017156200078657600080fd5b82525081516020918201929091019080838360005b83811015620007b55781810151838201526020016200079b565b50505050905090810190601f168015620007e35780820380516001836020036101000a031916815260200191505b50604052505050816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156200082457600080fd5b505afa15801562000839573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156200086357600080fd5b8101908080516040519392919084600160201b8211156200088357600080fd5b9083019060208201858111156200089957600080fd5b8251600160201b811182820188101715620008b357600080fd5b82525081516020918201929091019080838360005b83811015620008e2578181015183820152602001620008c8565b50505050905090810190601f168015620009105780820380516001836020036101000a031916815260200191505b5060405250505060405160200180806802ab734b834b637ba160bd1b81525060090183805190602001908083835b602083106200095f5780518252601f1990920191602091820191016200093e565b6001836020036101000a03801982511681845116808217855250505050505090500180602f60f81b81525060010182805190602001908083835b60208310620009ba5780518252601f19909201916020918201910162000999565b6001836020036101000a038019825116818451168082178552505050505050905001806d0814185cdcda5d994815985d5b1d60921b815250600e01925050506040516020818303038152906040529750816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801562000a4457600080fd5b505afa15801562000a59573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101562000a8357600080fd5b8101908080516040519392919084600160201b82111562000aa357600080fd5b90830190602082018581111562000ab957600080fd5b8251600160201b81118282018810171562000ad357600080fd5b82525081516020918201929091019080838360005b8381101562000b0257818101518382015260200162000ae8565b50505050905090810190601f16801562000b305780820380516001836020036101000a031916815260200191505b50604052505050816001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801562000b7157600080fd5b505afa15801562000b86573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101562000bb057600080fd5b8101908080516040519392919084600160201b82111562000bd057600080fd5b90830190602082018581111562000be657600080fd5b8251600160201b81118282018810171562000c0057600080fd5b82525081516020918201929091019080838360005b8381101562000c2f57818101518382015260200162000c15565b50505050905090810190601f16801562000c5d5780820380516001836020036101000a031916815260200191505b506040525050506040516020018080620554c560ec1b81525060030180602d60f81b81525060010183805190602001908083835b6020831062000cb25780518252601f19909201916020918201910162000c91565b6001836020036101000a03801982511681845116808217855250505050505090500180602f60f81b81525060010182805190602001908083835b6020831062000d0d5780518252601f19909201916020918201910162000cec565b6001836020036101000a03801982511681845116808217855250505050505090500180602d60f81b8152506001018061282b60f11b8152506002019250505060405160208183030381529060405296508b8b60405160200180836001600160a01b031660601b8152601401826001600160a01b031660601b81526014019250505060405160208183030381529060405280519060200120833060008054906101000a90046001600160a01b03168b8b60405162000dca9062001062565b80866001600160a01b03168152602001856001600160a01b03168152602001846001600160a01b031681526020018060200180602001838103835285818151815260200191508051906020019080838360005b8381101562000e3757818101518382015260200162000e1d565b50505050905090810190601f16801562000e655780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b8381101562000e9a57818101518382015260200162000e80565b50505050905090810190601f16801562000ec85780820380516001836020036101000a031916815260200191505b509750505050505050508190604051809103906000f590508015801562000ef3573d6000803e3d6000fd5b5095508560056000876001600160a01b03166001600160a01b031681526020019081526020016000206000866001600160a01b03166001600160a01b0316815260200190815260200160002060008061ffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055508560056000866001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060008061ffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550856001600160a01b0316846001600160a01b0316866001600160a01b03167f08acc1fcdfbc1f5df0b5f40cf612bea0fad8cf69205c4d2f1df8d33d713e64558d604051808261ffff16815260200191505060405180910390a450505050509695505050505050565b614b0880620010718339019056fe6101e06040527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c961012052600880546001600160a01b0316600160a01b1790553480156200004c57600080fd5b5060405162004b0838038062004b088339810160408190526200006f9162000550565b8180604051806040016040528060018152602001603160f81b81525084848160039080519060200190620000a5929190620003c8565b508051620000bb906004906020840190620003c8565b50506005805460ff1916601217905550815160208084019190912082519183019190912060c082905260e08190527f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6200011462000360565b60a0526200012481848462000364565b6080526101005250505050506001600160a01b0385166200014457600080fd5b6001600160a01b0383166200015857600080fd5b6001600160a01b0384166200016c57600080fd5b600880546001600160a01b038088166001600160a01b031990921691909117918290556001600160601b0319606087811b82166101c05286901b166101a05260408051630dfe168160e01b815290519290911691630dfe168191600480820192602092909190829003018186803b158015620001e757600080fd5b505afa158015620001fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200022291906200052c565b60601b6001600160601b031916610140526008546040805163d21220a760e01b815290516001600160a01b039092169163d21220a791600480820192602092909190829003018186803b1580156200027957600080fd5b505afa1580156200028e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b491906200052c565b60601b6001600160601b03191661016052600854604080516334324e9f60e21b815290516001600160a01b039092169163d0c93a7c91600480820192602092909190829003018186803b1580156200030b57600080fd5b505afa15801562000320573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003469190620005f0565b600290810b900b60e81b6101805250620006139350505050565b4690565b60008383836200037362000360565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b03168152602001955050505050506040516020818303038152906040528051906020012090509392505050565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826200040057600085556200044b565b82601f106200041b57805160ff19168380011785556200044b565b828001600101855582156200044b579182015b828111156200044b5782518255916020019190600101906200042e565b50620004599291506200045d565b5090565b5b808211156200045957600081556001016200045e565b80516001600160a01b03811681146200048c57600080fd5b919050565b600082601f830112620004a2578081fd5b81516001600160401b0380821115620004b757fe5b6040516020601f8401601f1916820181018381118382101715620004d757fe5b6040528382528584018101871015620004ee578485fd5b8492505b83831015620005115785830181015182840182015291820191620004f2565b838311156200052257848185840101525b5095945050505050565b6000602082840312156200053e578081fd5b620005498262000474565b9392505050565b600080600080600060a0868803121562000568578081fd5b620005738662000474565b9450620005836020870162000474565b9350620005936040870162000474565b60608701519093506001600160401b0380821115620005b0578283fd5b620005be89838a0162000491565b93506080880151915080821115620005d4578283fd5b50620005e38882890162000491565b9150509295509295909350565b60006020828403121562000602578081fd5b81518060020b811462000549578182fd5b60805160a05160c05160e05161010051610120516101405160601c6101605160601c6101805160e81c6101a05160601c6101c05160601c61441f620006e96000398061139b52508061164352806125dc528061262252806126a85280612e3a525050806105d95280610b0d5280610c075280610d2c5280610ea252806116045280611c115250806105a75280610ad65280610bd65280610d0a5280610e7652806115555280611bd252508061121e5250806124755250806124b752508061249652508061241c52508061244c525061441f6000f3fe6080604052600436106101085760003560e01c8062ebf5dd1461011157806306fdde0314610148578063095ea7b31461016a57806318160ddd146101975780631a87e87d146101b957806323b872dd146101d95780632c8958f6146101f9578063313ce567146102195780633644e5151461023b57806339509351146102505780633dd657c51461027057806370a08231146102905780637ecebe00146102b05780637f98aa71146102d05780638dbdbe6d146102f557806395d89b4114610317578063a457c2d71461032c578063a9059cbb1461034c578063ac2dc5621461036c578063c869623214610391578063d505accf146103b8578063dd62ed3e146103d85761010f565b3661010f57005b005b34801561011d57600080fd5b5061013161012c366004613fbe565b6103f8565b60405161013f929190614180565b60405180910390f35b34801561015457600080fd5b5061015d61072a565b60405161013f91906140f5565b34801561017657600080fd5b5061018a610185366004613def565b6107c1565b60405161013f91906140a4565b3480156101a357600080fd5b506101ac6107df565b60405161013f91906140c7565b3480156101c557600080fd5b5061010f6101d436600461402c565b6107e5565b3480156101e557600080fd5b5061018a6101f4366004613d3f565b610a13565b34801561020557600080fd5b5061010f610214366004613ec5565b610a9b565b34801561022557600080fd5b5061022e610b41565b60405161013f91906141d8565b34801561024757600080fd5b506101ac610b4a565b34801561025c57600080fd5b5061018a61026b366004613def565b610b59565b34801561027c57600080fd5b5061010f61028b366004613ec5565b610ba7565b34801561029c57600080fd5b506101ac6102ab366004613c77565b610c35565b3480156102bc57600080fd5b506101ac6102cb366004613c77565b610c54565b3480156102dc57600080fd5b506102e5610c75565b60405161013f949392919061405c565b610308610303366004613fff565b610d65565b60405161013f9392919061418e565b34801561032357600080fd5b5061015d61101e565b34801561033857600080fd5b5061018a610347366004613def565b61107f565b34801561035857600080fd5b5061018a610367366004613def565b6110e7565b34801561037857600080fd5b506103816110fb565b60405161013f94939291906140d0565b34801561039d57600080fd5b506103a6611124565b60405161013f969594939291906141a4565b3480156103c457600080fd5b5061010f6103d3366004613d7f565b6111af565b3480156103e457600080fd5b506101ac6103f3366004613c93565b611366565b600080600860149054906101000a90046001600160601b03166001600160601b031660011461042657600080fd5b600880546001600160a01b0316600160a11b1790556000610445611391565b505060085460405163051bb83360e01b81529294506001600160a01b03808616945063051bb8339361047d9350911690600401614048565b60006040518083038186803b15801561049557600080fd5b505afa1580156104a9573d6000803e3d6000fd5b50505050600086116104ba57600080fd5b60006104d687670de0b6b3a76400006104d16107df565b61143b565b60075490915060009081906104fa90600281810b9163010000009004900b856114d1565b6007549193509150600090819061052790600160301b8104600290810b91600160481b9004900b876114d1565b9092509050610536848361152b565b9750610542838261152b565b9650600061056461055b8a61055561153b565b906115da565b8d6104d16107df565b905060006105806105778a6105556115ea565b8e6104d16107df565b905061058c8a8361152b565b9950610598898261152b565b985089156105cc576105cc8b8d7f00000000000000000000000000000000000000000000000000000000000000008d611639565b88156105fe576105fe8b8d7f00000000000000000000000000000000000000000000000000000000000000008c611639565b60075461063990600281810b9163010000009004900b61061c61153b565b6106246115ea565b6008546001600160a01b03169392919061169c565b600754919750955061066390600160301b8104600290810b91600160481b9004900b61061c61153b565b9094509250610672338e611824565b8b6001600160a01b03167f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca948e8c8c6040516106af9392919061418e565b60405180910390a27f2fb985eb745b9e89bb1ab82e0f8ceb6bf94d4d60aed7e8196540c50161a5fe916106e2878661152b565b6106ec878661152b565b6040516106fa929190614180565b60405180910390a15050600880546001600160a01b0316600160a01b179055509599949850939650505050505050565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156107b65780601f1061078b576101008083540402835291602001916107b6565b820191906000526020600020905b81548152906001019060200180831161079957829003601f168201915b505050505090505b90565b60006107d56107ce61190e565b8484611912565b5060015b92915050565b60025490565b600854600160a01b90046001600160601b031660011461080457600080fd5b600880546001600160a01b0316600160a11b1790556000610823611391565b505060085460405163051bb83360e01b81529294506001600160a01b03808616945063051bb8339361085b9350911690600401614048565b60006040518083038186803b15801561087357600080fd5b505afa158015610887573d6000803e3d6000fd5b505060075460085460009350839250829182916108bf916001600160a01b0390911690600281810b9163010000009004900b306119fe565b6007546008549498509296509094509250600091829182918291610903916001600160a01b031690600160301b8104600290810b91600160481b9004900b306119fe565b9296509094509250905061092b600161091c888561152b565b610926888561152b565b611bb2565b6000610937898661152b565b90506000610945898661152b565b9050811580610952575080155b156109d057600080831161096757600061096a565b60015b90506000610976611391565b94505050505060008261099f5761099a610995858460ff16606461143b565b611c82565b6109b1565b6109b1610995868460ff16606461143b565b6008549091506109cc906001600160a01b0316308584611cca565b5050505b6109d861153b565b91506109e26115ea565b90506109ee8282611e46565b5050600880546001600160a01b0316600160a01b179055505050505050505050505050565b6000610a208484846120d8565b610a9084610a2c61190e565b610a8b85604051806060016040528060288152602001614314602891396001600160a01b038a16600090815260016020526040812090610a6a61190e565b6001600160a01b031681526020810191909152604001600020549190612221565b611912565b5060015b9392505050565b610aa36122b8565b6000841380610ab25750600083135b610abb57600080fd5b6000610ac982840184613e1a565b90508015610b0857610b037f0000000000000000000000000000000000000000000000000000000000000000610afd61190e565b876122d1565b610b3a565b610b3a7f0000000000000000000000000000000000000000000000000000000000000000610b3461190e565b866122d1565b5050505050565b60055460ff1690565b6000610b54612418565b905090565b60006107d5610b6661190e565b84610a8b8560016000610b7761190e565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906124e2565b610baf6122b8565b6000610bb961190e565b90506000610bc983850185613c77565b90508515610bfc57610bfc7f000000000000000000000000000000000000000000000000000000000000000083886122d1565b8415610c2d57610c2d7f000000000000000000000000000000000000000000000000000000000000000083876122d1565b505050505050565b6001600160a01b0381166000908152602081905260409020545b919050565b6001600160a01b03811660009081526006602052604081206107d99061253a565b6000806000806000600860009054906101000a90046001600160a01b03166001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015610ccb57600080fd5b505afa158015610cdf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d039190613f15565b50506008547f00000000000000000000000000000000000000000000000000000000000000009b7f00000000000000000000000000000000000000000000000000000000000000009b509399506001600160a01b031697509195505050505050565b6000806000600860149054906101000a90046001600160601b03166001600160601b0316600114610d9557600080fd5b60088054600160a11b6001600160a01b03918216179091558416610db857600080fd5b600086118015610dc85750600085115b610dd157600080fd5b6000610ddb61190e565b90506000610de76107df565b9050610e6a60008989610df861153b565b610e006115ea565b60408051608081018252600754600281810b810b810b835263010000008204810b810b810b6020840152600160301b8204810b810b810b93830193909352600160481b9004820b820b90910b60608201526008546001600160a01b0316959493929190889061253e565b91965094509250610e9d7f00000000000000000000000000000000000000000000000000000000000000008330876125da565b610ec97f00000000000000000000000000000000000000000000000000000000000000008330866125da565b80610f09576103e88511610ef85760405162461bcd60e51b8152600401610eef90614148565b60405180910390fd5b610f028484611e46565b5050610f92565b84610f265760405162461bcd60e51b8152600401610eef90614164565b6007546008546000918291610f57916001600160a01b0390911690600281810b9163010000009004900b898961169c565b6007549193509150610f8d90600160301b8104600290810b91600160481b9004900b610f8389866115da565b61062489866115da565b505050505b4715610fa257610fa28247612762565b610fac8686612856565b856001600160a01b0316826001600160a01b03167f4e2ca0515ed1aef1395f66b5303bb5d6f1bf9d61a353fa53f73f8ac9973fa9f6868689604051610ff39392919061418e565b60405180910390a35050600880546001600160a01b0316600160a01b17905591959094509092509050565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156107b65780601f1061078b576101008083540402835291602001916107b6565b60006107d561108c61190e565b84610a8b856040518060600160405280602581526020016143ee60259139600160006110b661190e565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190612221565b60006107d56110f461190e565b84846120d8565b600754600281810b9163010000008104820b91600160301b8204810b91600160481b9004900b84565b60408051608081018252600754600281810b810b810b835263010000008204810b810b810b6020840152600160301b8204810b810b810b93830193909352600160481b9004820b820b90910b60608201526008546000918291829182918291829161119c916001600160a01b03909116908390612934565b949b939a50919850965094509092509050565b83421115611204576040805162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e65000000604482015290519081900360640190fd5b6001600160a01b03871660009081526006602052604081207f00000000000000000000000000000000000000000000000000000000000000009089908990899061124d9061253a565b8960405160200180878152602001866001600160a01b03168152602001856001600160a01b03168152602001848152602001838152602001828152602001965050505050505060405160208183030381529060405280519060200120905060006112b6826129cb565b905060006112c682878787612a17565b9050896001600160a01b0316816001600160a01b03161461132e576040805162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e61747572650000604482015290519081900360640190fd5b6001600160a01b038a16600090815260066020526040902061134f90612b86565b61135a8a8a8a611912565b50505050505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b60008060008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166338d772806040518163ffffffff1660e01b815260040160a06040518083038186803b1580156113f257600080fd5b505afa158015611406573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061142a9190613ccb565b945094509450945094509091929394565b6000838302816000198587098281108382030391505080841161145d57600080fd5b8061146d57508290049050610a94565b8385870960008581038616958690049560026003880281188089028203028089028203028089028203028089028203028089028203028089029091030291819003819004600101858411909403939093029190930391909104170290509392505050565b60085460009081906114ef906001600160a01b031686868630612b8f565b60085491935091506000908190611511906001600160a01b0316308989612d5c565b9150915061152160008383611bb2565b5050935093915050565b808201828110156107d957600080fd5b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319061158a903090600401614048565b60206040518083038186803b1580156115a257600080fd5b505afa1580156115b6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b549190613fa6565b808203828111156107d957600080fd5b6040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a082319061158a903090600401614048565b83801561167757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316145b1561168b576116868184612e23565b611696565b6116968284836122d1565b50505050565b600080806116b66001600160a01b03891686868a8a612eaf565b90506001600160801b0381161561181957876001600160a01b031663aafe29c030308a8a863060405160200180826001600160a01b031681526020019150506040516020818303038152906040526040518763ffffffff1660e01b815260040180876001600160a01b03168152602001866001600160a01b031681526020018560020b81526020018460020b8152602001836001600160801b0316815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561178f578181015183820152602001611777565b50505050905090810190601f1680156117bc5780820380516001836020036101000a031916815260200191505b50975050505050505050606060405180830381600087803b1580156117e057600080fd5b505af11580156117f4573d6000803e3d6000fd5b505050506040513d606081101561180a57600080fd5b50805160209091015190935091505b509550959350505050565b6001600160a01b0382166118695760405162461bcd60e51b815260040180806020018281038252602181526020018061435c6021913960400191505060405180910390fd5b61187582600083612851565b6118b28160405180606001604052806022815260200161423f602291396001600160a01b0385166000908152602081905260409020549190612221565b6001600160a01b0383166000908152602081905260409020556002546118d89082612f41565b6002556040805182815290516000916001600160a01b0385169160008051602061433c8339815191529181900360200190a35050565b3390565b6001600160a01b0383166119575760405162461bcd60e51b81526004018080602001828103825260248152602001806143a26024913960400191505060405180910390fd5b6001600160a01b03821661199c5760405162461bcd60e51b81526004018080602001828103825260228152602001806142616022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600080808080611a186001600160a01b038a168989612f9e565b50909150506001600160801b03811615611ba6576040805163a34123a760e01b815260028a810b600483015289900b60248201526001600160801b038316604482015281516001600160a01b038c169263a34123a792606480820193918290030181600087803b158015611a8b57600080fd5b505af1158015611a9f573d6000803e3d6000fd5b505050506040513d6040811015611ab557600080fd5b508051602090910151909550935084151580611ad15750600084115b15611ba657604080516309e3d67b60e31b81526001600160a01b03888116600483015260028b810b60248401528a900b60448301526001600160801b0360648301819052608483015282516000938493928e1692634f1eb3d89260a4808301939282900301818787803b158015611b4757600080fd5b505af1158015611b5b573d6000803e3d6000fd5b505050506040513d6040811015611b7157600080fd5b5080516020909101516001600160801b039182169350169050611b9482886115da565b611b9e82886115da565b909550935050505b50945094509450949050565b600080611bbd611391565b509350935050506000841115611c0657611c067f000000000000000000000000000000000000000000000000000000000000000083611c01878560ff16606461143b565b6122d1565b8215611c4057611c407f000000000000000000000000000000000000000000000000000000000000000083611c01868560ff16606461143b565b7ff8994d9c768d599c5c6e92d52cd9cc24762cd773384c7a4612796773c56a86a6858585604051611c73939291906140af565b60405180910390a15050505050565b6000600160ff1b8210611cc65760405162461bcd60e51b81526004018080602001828103825260288152602001806143c66028913960400191505060405180910390fd5b5090565b6000611cde856001600160a01b031661304c565b505090506000620f42408261c350026001600160a01b031681611cfd57fe5b049050600084611d0f57818301611d13565b8183035b9050866001600160a01b031663128acb08878787858a6040516020018082151581526020019150506040516020818303038152906040526040518663ffffffff1660e01b815260040180866001600160a01b031681526020018515158152602001848152602001836001600160a01b0316815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611dc2578181015183820152602001611daa565b50505050905090810190601f168015611def5780820380516001836020036101000a031916815260200191505b5096505050505050506040805180830381600087803b158015611e1157600080fd5b505af1158015611e25573d6000803e3d6000fd5b505050506040513d6040811015611e3b57600080fd5b505050505050505050565b600080611e51613bd8565b600854611e66906001600160a01b03166130ce565b600290810b810b60a088015290810b810b608087015290810b810b606086015290810b810b604085015290810b810b6020840181905291810b900b808352600854611ebf926001600160a01b039091169190888861169c565b825160078054602086015162ffffff19909116600293840b62ffffff9081169190911765ffffff000000191663010000009290940b160291909117905590935091506000611f0d86856115da565b90506000611f1b86856115da565b9050600080831180611f2d5750600082115b156120665760408401516060850151600854600092611f5b926001600160a01b039092169187918791612eaf565b608086015160a0870151600854929350600092611f87926001600160a01b039091169188918891612eaf565b9050816001600160801b0316816001600160801b03161015611ff9576040860151600780546060890151600290810b62ffffff908116600160481b0262ffffff60481b199590920b16600160301b0262ffffff60301b1990921691909117929092169190911790559091508190612063565b806001600160801b0316826001600160801b031610156120635760808601516007805460a0890151600290810b62ffffff908116600160481b0262ffffff60481b199590920b16600160301b0262ffffff60301b1990921691909117929092169190911790559150815b50505b6001600160801b038116156120cd5760075460085460009182916120ad916001600160a01b0390911690600160301b8104600290810b91600160481b9004900b888861169c565b90925090506120bc888361152b565b97506120c8878261152b565b965050505b505050509250929050565b6001600160a01b03831661211d5760405162461bcd60e51b815260040180806020018281038252602581526020018061437d6025913960400191505060405180910390fd5b6001600160a01b0382166121625760405162461bcd60e51b815260040180806020018281038252602381526020018061421c6023913960400191505060405180910390fd5b61216d838383612851565b6121aa81604051806060016040528060268152602001614283602691396001600160a01b0386166000908152602081905260409020549190612221565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546121d990826124e2565b6001600160a01b0380841660008181526020818152604091829020949094558051858152905191939287169260008051602061433c83398151915292918290030190a3505050565b600081848411156122b05760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561227557818101518382015260200161225d565b50505050905090810190601f1680156122a25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6008546001600160a01b031633146122cf57600080fd5b565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b6020831061234d5780518252601f19909201916020918201910161232e565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146123af576040519150601f19603f3d011682016040523d82523d6000602084013e6123b4565b606091505b50915091508180156123e25750805115806123e257508080602001905160208110156123df57600080fd5b50515b610b3a576040805162461bcd60e51b815260206004820152600260248201526114d560f21b604482015290519081900360640190fd5b60007f000000000000000000000000000000000000000000000000000000000000000061244361317b565b141561247057507f00000000000000000000000000000000000000000000000000000000000000006107be565b6124db7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000061317f565b90506107be565b600082820183811015610a94576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b5490565b60008060008060008060006125548f8f8a612934565b50509350935093509350600061257d8c612577858861152b90919063ffffffff16565b9061152b565b9050600061258f8c612577878661152b565b90508a158061259d57508115155b806125a757508015155b6125ad57fe5b6125ba8f8f84848f6131e1565b809950819a50829b50505050505050505050985098509895505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b031614801561261b5750804710155b1561273a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561267b57600080fd5b505af115801561268f573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb92506126e291508590859060040161408b565b602060405180830381600087803b1580156126fc57600080fd5b505af1158015612710573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127349190613e36565b50611696565b6001600160a01b038316301415612756576116868483836122d1565b61169684848484613275565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b602083106127ae5780518252601f19909201916020918201910161278f565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612810576040519150601f19603f3d011682016040523d82523d6000602084013e612815565b606091505b5050905080612851576040805162461bcd60e51b815260206004820152600360248201526253544560e81b604482015290519081900360640190fd5b505050565b6001600160a01b0382166128b1576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6128bd60008383612851565b6002546128ca90826124e2565b6002556001600160a01b0382166000908152602081905260409020546128f090826124e2565b6001600160a01b03831660008181526020818152604080832094909455835185815293519293919260008051602061433c8339815191529281900390910190a35050565b60008060008060008061295089886000015189602001516133c5565b939950919750955093509150876129bf57600080600080600061297c8e8d604001518e606001516133c5565b9398509196509450925090506129928b8661152b565b9a5061299e8a8561152b565b99506129aa898461152b565b98506129b6888361152b565b97509450505050505b93975093979195509350565b60006129d5612418565b82604051602001808061190160f01b81525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050919050565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115612a6e5760405162461bcd60e51b81526004018080602001828103825260228152602001806142d06022913960400191505060405180910390fd5b8360ff16601b1480612a8357508360ff16601c145b612abe5760405162461bcd60e51b81526004018080602001828103825260228152602001806142f26022913960400191505060405180910390fd5b600060018686868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015612b1a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612b7d576040805162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b604482015290519081900360640190fd5b95945050505050565b80546001019055565b60008080612ba76001600160a01b0389168888612f9e565b505090506000612bc9826001600160801b031687670de0b6b3a764000061143b565b9050886001600160a01b031663a34123a78989612be58561340a565b6040518463ffffffff1660e01b8152600401808460020b81526020018360020b8152602001826001600160801b0316815260200193505050506040805180830381600087803b158015612c3757600080fd5b505af1158015612c4b573d6000803e3d6000fd5b505050506040513d6040811015612c6157600080fd5b508051602090910151909450925083151580612c7d5750600083115b15612d5057886001600160a01b0316634f1eb3d8868a8a612c9d8961340a565b612ca68961340a565b6040518663ffffffff1660e01b815260040180866001600160a01b031681526020018560020b81526020018460020b8152602001836001600160801b03168152602001826001600160801b03168152602001955050505050506040805180830381600087803b158015612d1857600080fd5b505af1158015612d2c573d6000803e3d6000fd5b505050506040513d6040811015612d4257600080fd5b50516001600160801b031693505b50509550959350505050565b600080612d6a86858561344e565b50604080516309e3d67b60e31b81526001600160a01b038781166004830152600287810b602484015286900b60448301526001600160801b03606483018190526084830152825190891692634f1eb3d89260a480820193918290030181600087803b158015612dd857600080fd5b505af1158015612dec573d6000803e3d6000fd5b505050506040513d6040811015612e0257600080fd5b5080516020909101516001600160801b039182169891169650945050505050565b604051632e1a7d4d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90612e6f9085906004016140c7565b600060405180830381600087803b158015612e8957600080fd5b505af1158015612e9d573d6000803e3d6000fd5b50505050612eab8183612762565b5050565b600080866001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015612eeb57600080fd5b505afa158015612eff573d6000803e3d6000fd5b505050506040513d60e0811015612f1557600080fd5b50519050612f3681612f2686613507565b612f2f86613507565b898961382e565b979650505050505050565b600082821115612f98576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600080600080600030905062ffffff861662ffffff88168260181b1760181b179150876001600160a01b031663514ea4bf836040518263ffffffff1660e01b81526004018082815260200191505060c06040518083038186803b15801561300457600080fd5b505afa158015613018573d6000803e3d6000fd5b505050506040513d60c081101561302e57600080fd5b508051608082015160a090920151909a919950975095505050505050565b6000806000836001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b15801561308a57600080fd5b505afa15801561309e573d6000803e3d6000fd5b505050506040513d60e08110156130b457600080fd5b508051602082015160609092015190969195509350915050565b60008060008060008060006130e1611391565b505060405163802036f560e01b8152919350506001600160a01b038316915063802036f590613114908b90600401614048565b60c060405180830381600087803b15801561312e57600080fd5b505af1158015613142573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131669190613e52565b949d939c50919a509850965090945092505050565b4690565b600083838361318c61317b565b3060405160200180868152602001858152602001848152602001838152602001826001600160a01b03168152602001955050505050506040516020818303038152906040528051906020012090509392505050565b60008080836132055750869050858082116131fc57806131fe565b815b925061326a565b856132175750856131fe81858761143b565b8461322a578791506131fe82858861143b565b61323587878761143b565b91508782101561324c5750856131fe81858761143b565b87915061325a82868861143b565b905061326782858861143b565b92505b955095509592505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b178152925182516000948594938a169392918291908083835b602083106132f95780518252601f1990920191602091820191016132da565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461335b576040519150601f19603f3d011682016040523d82523d6000602084013e613360565b606091505b509150915081801561338e57508051158061338e575080806020019051602081101561338b57600080fd5b50515b610c2d576040805162461bcd60e51b815260206004820152600360248201526229aa2360e91b604482015290519081900360640190fd5b60008060008060006133d888888861344e565b90506001600160801b038116156133ff576133f48888886138f0565b929750909550935091505b939792965093509350565b6000600160801b8210611cc65760405162461bcd60e51b81526004018080602001828103825260278152602001806142a96027913960400191505060405180910390fd5b60006134646001600160a01b0385168484612f9e565b50909150506001600160801b03811615610a9457836001600160a01b031663a34123a7848460006040518463ffffffff1660e01b8152600401808460020b81526020018360020b815260200182815260200193505050506040805180830381600087803b1580156134d457600080fd5b505af11580156134e8573d6000803e3d6000fd5b505050506040513d60408110156134fe57600080fd5b50509392505050565b60008060008360020b1261351e578260020b613526565b8260020b6000035b9050620d89e8811115613564576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b60006001821661357857600160801b61358a565b6ffffcb933bd6fad37aa2d162d1a5940015b6001600160881b0316905060028216156135b4576ffff97272373d413259a46990580e213a0260801c5b60048216156135d3576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b60088216156135f2576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b6010821615613611576fffcb9843d60f6159c9db58835c9266440260801c5b6020821615613630576fff973b41fa98c081472e6896dfb254c00260801c5b604082161561364f576fff2ea16466c96a3843ec78b326b528610260801c5b608082161561366e576ffe5dee046a99a2a811c461f1969c30530260801c5b61010082161561368e576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b6102008216156136ae576ff987a7253ac413176f2b074cf7815e540260801c5b6104008216156136ce576ff3392b0822b70005940c7a398e4b70f30260801c5b6108008216156136ee576fe7159475a2c29b7443b29c7fa6e889d90260801c5b61100082161561370e576fd097f3bdfd2022b8845ad8f792aa58250260801c5b61200082161561372e576fa9f746462d870fdf8a65dc1f90e061e50260801c5b61400082161561374e576f70d869a156d2a1b890bb3df62baf32f70260801c5b61800082161561376e576f31be135f97d08fd981231505542fcfa60260801c5b6201000082161561378f576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b620200008216156137af576e5d6af8dedb81196699c329225ee6040260801c5b620400008216156137ce576d2216e584f5fa1ea926041bedfe980260801c5b620800008216156137eb576b048a170391f7dc42444e8fa20260801c5b60008460020b131561380657806000198161380257fe5b0490505b600160201b81061561381957600161381c565b60005b60ff16602082901c0192505050919050565b6000836001600160a01b0316856001600160a01b0316111561384e579293925b846001600160a01b0316866001600160a01b0316116138795761387285858561393c565b9050612b7d565b836001600160a01b0316866001600160a01b031610156138db5760006138a087868661393c565b905060006138af87898661399f565b9050806001600160801b0316826001600160801b0316106138d057806138d2565b815b92505050612b7d565b6138e685858461399f565b9695505050505050565b60008060008060008060006139068a8a8a612f9e565b92509250925060008061391b8c868d8d6139e4565b9099509750506001600160801b039283169550501691505093509350935093565b6000826001600160a01b0316846001600160a01b0316111561395c579192915b600061397f856001600160a01b0316856001600160a01b0316600160601b61143b565b9050612b7d61399a84838888036001600160a01b031661143b565b613a7b565b6000826001600160a01b0316846001600160a01b031611156139bf579192915b6139dc61399a83600160601b8787036001600160a01b031661143b565b949350505050565b6000806000866001600160a01b031663e76c01e46040518163ffffffff1660e01b815260040160e06040518083038186803b158015613a2257600080fd5b505afa158015613a36573d6000803e3d6000fd5b505050506040513d60e0811015613a4c57600080fd5b50519050613a6c81613a5d87613507565b613a6687613507565b89613a91565b92509250505b94509492505050565b806001600160801b0381168114610c4f57600080fd5b600080836001600160a01b0316856001600160a01b03161115613ab2579293925b846001600160a01b0316866001600160a01b031611613add57613ad6858585613b2c565b9150613a72565b836001600160a01b0316866001600160a01b03161015613b1657613b02868585613b2c565b9150613b0f858785613b95565b9050613a72565b613b21858585613b95565b905094509492505050565b6000826001600160a01b0316846001600160a01b03161115613b4c579192915b836001600160a01b0316613b85606060ff16846001600160801b0316901b8686036001600160a01b0316866001600160a01b031661143b565b81613b8c57fe5b04949350505050565b6000826001600160a01b0316846001600160a01b03161115613bb5579192915b6139dc826001600160801b03168585036001600160a01b0316600160601b61143b565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60008083601f840112613c1e578182fd5b5081356001600160401b03811115613c34578182fd5b602083019150836020828501011115613c4c57600080fd5b9250929050565b8051600281900b8114610c4f57600080fd5b805161ffff81168114610c4f57600080fd5b600060208284031215613c88578081fd5b8135610a94816141e6565b60008060408385031215613ca5578081fd5b8235613cb0816141e6565b91506020830135613cc0816141e6565b809150509250929050565b600080600080600060a08688031215613ce2578081fd5b8551613ced816141e6565b6020870151909550613cfe816141e6565b6040870151909450613d0f816141e6565b6060870151909350613d208161420c565b6080870151909250613d318161420c565b809150509295509295909350565b600080600060608486031215613d53578283fd5b8335613d5e816141e6565b92506020840135613d6e816141e6565b929592945050506040919091013590565b600080600080600080600060e0888a031215613d99578182fd5b8735613da4816141e6565b96506020880135613db4816141e6565b955060408801359450606088013593506080880135613dd28161420c565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215613e01578182fd5b8235613e0c816141e6565b946020939093013593505050565b600060208284031215613e2b578081fd5b8135610a94816141fe565b600060208284031215613e47578081fd5b8151610a94816141fe565b60008060008060008060c08789031215613e6a578384fd5b613e7387613c53565b9550613e8160208801613c53565b9450613e8f60408801613c53565b9350613e9d60608801613c53565b9250613eab60808801613c53565b9150613eb960a08801613c53565b90509295509295509295565b60008060008060608587031215613eda578182fd5b843593506020850135925060408501356001600160401b03811115613efd578283fd5b613f0987828801613c0d565b95989497509550505050565b600080600080600080600060e0888a031215613f2f578081fd5b8751613f3a816141e6565b9650613f4860208901613c53565b9550613f5660408901613c65565b9450613f6460608901613c65565b93506080880151613f748161420c565b60a0890151909350613f858161420c565b60c0890151909250613f96816141fe565b8091505092959891949750929550565b600060208284031215613fb7578081fd5b5051919050565b600080600060608486031215613fd2578081fd5b833592506020840135613fe4816141e6565b91506040840135613ff4816141fe565b809150509250925092565b600080600060608486031215614013578081fd5b83359250602084013591506040840135613ff4816141e6565b60006020828403121561403d578081fd5b8135610a948161420c565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015261ffff919091166040830152909116606082015260800190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b92151583526020830191909152604082015260600190565b90815260200190565b600294850b815292840b602084015290830b604083015290910b606082015260800190565b6000602080835283518082850152825b8181101561412157858101830151858201604001528201614105565b818111156141325783604083870101525b50601f01601f1916929092016040019392505050565b602080825260029082015261135360f21b604082015260600190565b602080825260029082015261495360f01b604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b9586526020860194909452604085019290925260608401526001600160801b0390811660808401521660a082015260c00190565b60ff91909116815260200190565b6001600160a01b03811681146141fb57600080fd5b50565b80151581146141fb57600080fd5b60ff811681146141fb57600080fdfe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636553616665436173743a2076616c756520646f65736e27742066697420696e20313238206269747345434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c756545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737353616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e7432353645524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa164736f6c6343000706000aa164736f6c6343000706000a0000000000000000000000004b9f4d2435ef65559567e5dbfc1bbb37abc43b570000000000000000000000001e3881227010c8dcdfa2f11833d3d70a00893f94000000000000000000000000cbe0ac9a00a69aa28099091b2ceac5941ec435210000000000000000000000001e3881227010c8dcdfa2f11833d3d70a00893f940000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000028
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004b9f4d2435ef65559567e5dbfc1bbb37abc43b570000000000000000000000001e3881227010c8dcdfa2f11833d3d70a00893f94000000000000000000000000cbe0ac9a00a69aa28099091b2ceac5941ec435210000000000000000000000001e3881227010c8dcdfa2f11833d3d70a00893f940000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000028
-----Decoded View---------------
Arg [0] : _algebraFactory (address): 0x4b9f4d2435ef65559567e5dbfc1bbb37abc43b57
Arg [1] : _governance (address): 0x1e3881227010c8dcdfa2f11833d3d70a00893f94
Arg [2] : _uniStrategy (address): 0xcbe0ac9a00a69aa28099091b2ceac5941ec43521
Arg [3] : _indexFund (address): 0x1e3881227010c8dcdfa2f11833d3d70a00893f94
Arg [4] : _WETH (address): 0x4f9a0e7fd2bf6067db6994cf12e4495df938e6e9
Arg [5] : _indexFundPercentage (uint8): 10
Arg [6] : _swapPercentage (uint8): 40
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000004b9f4d2435ef65559567e5dbfc1bbb37abc43b57
Arg [1] : 0000000000000000000000001e3881227010c8dcdfa2f11833d3d70a00893f94
Arg [2] : 000000000000000000000000cbe0ac9a00a69aa28099091b2ceac5941ec43521
Arg [3] : 0000000000000000000000001e3881227010c8dcdfa2f11833d3d70a00893f94
Arg [4] : 0000000000000000000000004f9a0e7fd2bf6067db6994cf12e4495df938e6e9
Arg [5] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000028
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.