Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- PoolV1
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2023-08-29T05:24:07.166698Z
contracts/pool/PoolV1.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.19; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import {SignedIntOps} from "../lib/SignedInt.sol"; import {MathUtils} from "../lib/MathUtils.sol"; import {PositionUtils} from "../lib/PositionUtils.sol"; import {IAipxOracle} from "../interfaces/IAipxOracle.sol"; import {ILPToken} from "../interfaces/ILPToken.sol"; import {IPool, Side, TokenWeight} from "../interfaces/IPool.sol"; import { PoolStorage, Position, PoolTokenInfo, Fee, AssetInfo, PRECISION, LP_INITIAL_PRICE, MAX_BASE_SWAP_FEE, MAX_TAX_BASIS_POINT, MAX_POSITION_FEE, MAX_LIQUIDATION_FEE, MAX_INTEREST_RATE, MAX_ASSETS, MAX_MAINTENANCE_MARGIN } from "./PoolStorage.sol"; import {PoolErrors} from "./PoolErrors.sol"; import {IPoolHook} from "../interfaces/IPoolHook.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; uint256 constant USD_VALUE_DECIMAL = 30; uint256 constant MIN_SWAP_FEE = 10000000; struct IncreasePositionVars { uint256 reserveAdded; uint256 collateralAmount; uint256 collateralValueAdded; uint256 feeValue; uint256 daoFee; uint256 indexPrice; uint256 sizeChanged; uint256 feeAmount; uint256 totalLpFee; } /// @notice common variable used accross decrease process struct DecreasePositionVars { /// @notice santinized input: collateral value able to be withdraw uint256 collateralReduced; /// @notice santinized input: position size to decrease, capped to position's size uint256 sizeChanged; /// @notice current price of index uint256 indexPrice; /// @notice current price of collateral uint256 collateralPrice; /// @notice postion's remaining collateral value in USD after decrease position uint256 remainingCollateral; /// @notice reserve reduced due to reducion process uint256 reserveReduced; /// @notice total value of fee to be collect (include dao fee and LP fee) uint256 feeValue; /// @notice amount of collateral taken as fee uint256 daoFee; /// @notice real transfer out amount to user uint256 payout; /// @notice 'net' PnL (fee not counted) int256 pnl; int256 poolAmountReduced; uint256 totalLpFee; } contract PoolV1 is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable, PoolStorage, IPool { using SignedIntOps for int256; using SafeERC20 for IERC20; using SafeCast for uint256; using SafeCast for int256; /* =========== MODIFIERS ========== */ modifier onlyOrderManager() { _requireOrderManager(); _; } modifier onlyAsset(address _token) { _validateAsset(_token); _; } modifier onlyListedToken(address _token) { _requireListedToken(_token); _; } // modifier onlyController() { // _onlyController(); // _; // } // constructor() { // _disableInitializers(); // } /* ======== INITIALIZERS ========= */ function initialize( uint256 _maxLeverage, uint256 _positionFee, uint256 _liquidationFee, uint256 _maintainanceMargin ) external initializer { __Ownable_init(); __ReentrancyGuard_init(); _setMaxLeverage(_maxLeverage); _setPositionFee(_positionFee, _liquidationFee); _setMaintenanceMargin(_maintainanceMargin); fee.daoFee = PRECISION; } // ========= View functions ========= function validateToken( address _indexToken, address _collateralToken, Side _side, bool _isIncrease ) external view returns (bool) { return _validateToken(_indexToken, _collateralToken, _side, _isIncrease); } function getPoolAsset( address _token ) external view returns (AssetInfo memory) { return _getPoolAsset(_token); } function getAllTranchesLength() external view returns (uint256) { return allTranches.length; } function getPoolValue(bool _max) external view returns (uint256) { return _getPoolValue(_max); } function getTrancheValue(address _tranche, bool _max) external view returns (uint256 sum) { _validateTranche(_tranche); return _getTrancheValue(_tranche, _max); } // function calcSwapOutput(address _tokenIn, address _tokenOut, uint256 _amountIn) // external // view // returns (uint256 amountOut, uint256 feeAmount) // { // return _calcSwapOutput(_tokenIn, _tokenOut, _amountIn); // } // function calcRemoveLiquidity(address _tranche, address _tokenOut, uint256 _lpAmount) // external // view // returns (uint256 outAmount, uint256 outAmountAfterFee, uint256 feeAmount) // { // (outAmount, outAmountAfterFee, feeAmount, ) = _calcRemoveLiquidity(_tranche, _tokenOut, _lpAmount); // } // function calcAddLiquidity(address _tranche, address _token, uint256 _amountIn) // external // view // returns (uint256 amountInAfterDaoFee, uint256 daoFee, uint256 lpAmount) // { // return _calcAddLiquidity(_tranche, _token, _amountIn); // } // ============= Mutative functions ============= function addLiquidity( address _tranche, address _token, uint256 _amountIn, uint256 _minLpAmount, address _to ) external nonReentrant onlyListedToken(_token) { _validateTranche(_tranche); _accrueInterest(_token); IERC20(_token).safeTransferFrom(msg.sender, address(this), _amountIn); _amountIn = _requireAmount(_getAmountIn(_token)); (uint256 amountInAfterDaoFee, uint256 daoFee, uint256 lpAmount) = _calcAddLiquidity(_tranche, _token, _amountIn); if (lpAmount < _minLpAmount) { revert PoolErrors.SlippageExceeded(); } poolTokens[_token].feeReserve += daoFee; trancheAssets[_tranche][_token].poolAmount += amountInAfterDaoFee; refreshVirtualPoolValue(); ILPToken(_tranche).mint(_to, lpAmount); emit LiquidityAdded(_tranche, msg.sender, _token, _amountIn, lpAmount, daoFee); } function removeLiquidity( address _tranche, address _tokenOut, uint256 _lpAmount, uint256 _minOut, address _to ) external nonReentrant onlyAsset(_tokenOut) { _validateTranche(_tranche); _accrueInterest(_tokenOut); _requireAmount(_lpAmount); ILPToken lpToken = ILPToken(_tranche); (, uint256 outAmountAfterFee, uint256 daoFee, uint256 tokenOutPrice) = _calcRemoveLiquidity(_tranche, _tokenOut, _lpAmount); if (outAmountAfterFee < _minOut) { revert PoolErrors.SlippageExceeded(); } poolTokens[_tokenOut].feeReserve += daoFee; _decreaseTranchePoolAmount(_tranche, _tokenOut, outAmountAfterFee + daoFee); refreshVirtualPoolValue(); lpToken.burnFrom(msg.sender, _lpAmount); _doTransferOut(_tokenOut, _to, outAmountAfterFee); emit LiquidityRemoved(_tranche, msg.sender, _tokenOut, _lpAmount, outAmountAfterFee, daoFee); } function swap( address _tokenIn, address _tokenOut, uint256 _minOut, address _to, bytes calldata extradata ) external nonReentrant onlyListedToken(_tokenIn) onlyAsset(_tokenOut) { if (_tokenIn == _tokenOut) { revert PoolErrors.SameTokenSwap(_tokenIn); } _accrueInterest(_tokenIn); _accrueInterest(_tokenOut); uint256 amountIn = _requireAmount(_getAmountIn(_tokenIn)); (uint256 amountOutAfterFee, uint256 swapFee) = _calcSwapOutput(_tokenIn, _tokenOut, amountIn); if (amountOutAfterFee < _minOut) { revert PoolErrors.SlippageExceeded(); } (uint256 daoFee, uint256 lpFee) = _calcDaoFee(swapFee); poolTokens[_tokenIn].feeReserve += daoFee; _rebalanceTranches(_tokenIn, amountIn - swapFee, _tokenOut, amountOutAfterFee, lpFee); _validateMaxLiquidity(_tokenIn); _doTransferOut(_tokenOut, _to, amountOutAfterFee); emit Swap(msg.sender, _tokenIn, _tokenOut, amountIn, amountOutAfterFee, swapFee); if (address(poolHook) != address(0)) { poolHook.postSwap( _to, _tokenIn, _tokenOut, abi.encode(amountIn, amountOutAfterFee, swapFee, extradata) ); } } function increasePosition( address _owner, address _indexToken, address _collateralToken, uint256 _sizeChanged, Side _side ) external onlyOrderManager { _requireValidTokenPair(_indexToken, _collateralToken, _side, true); IncreasePositionVars memory vars; vars.collateralAmount = _requireAmount(_getAmountIn(_collateralToken)); uint256 collateralPrice = _getCollateralPrice(_collateralToken, true); vars.collateralValueAdded = collateralPrice * vars.collateralAmount; uint256 borrowIndex = _accrueInterest(_collateralToken); bytes32 key = _getPositionKey(_owner, _indexToken, _collateralToken, _side); Position memory position = positions[key]; vars.indexPrice = _getIndexPrice(_indexToken, _side, true); vars.sizeChanged = _sizeChanged; vars.feeValue = _calcPositionFee(position, vars.sizeChanged, borrowIndex); vars.feeAmount = vars.feeValue / collateralPrice; (vars.daoFee, vars.totalLpFee) = _calcDaoFee(vars.feeAmount); vars.reserveAdded = vars.sizeChanged / collateralPrice; position.entryPrice = PositionUtils.calcAveragePrice( _side, position.size, position.size + vars.sizeChanged, position.entryPrice, vars.indexPrice, 0 ); position.collateralValue = MathUtils.zeroCapSub( position.collateralValue + vars.collateralValueAdded, vars.feeValue ); position.size = position.size + vars.sizeChanged; position.borrowIndex = borrowIndex; position.reserveAmount += vars.reserveAdded; if (vars.sizeChanged != 0 && (position.size > position.collateralValue * maxLeverage)){ revert PoolErrors.InvalidLeverage(position.size, position.collateralValue, maxLeverage); } _validatePosition(position, _collateralToken, _side, vars.indexPrice); _reservePoolAsset(key, vars, _indexToken, _collateralToken, _side); positions[key] = position; emit IncreasePosition( key, _owner, _collateralToken, _indexToken, vars.collateralAmount, vars.sizeChanged, _side, vars.indexPrice, vars.feeValue ); emit UpdatePosition( key, position.size, position.collateralValue, position.entryPrice, position.borrowIndex, position.reserveAmount, vars.indexPrice ); if (address(poolHook) != address(0)) { poolHook.postIncreasePosition( _owner, _indexToken, _collateralToken, _side, abi.encode( _sizeChanged, vars.collateralValueAdded, vars.feeValue ) ); } } function decreasePosition( address _owner, address _indexToken, address _collateralToken, uint256 _collateralChanged, uint256 _sizeChanged, Side _side, address _receiver ) external onlyOrderManager { _requireValidTokenPair(_indexToken, _collateralToken, _side, false); uint256 borrowIndex = _accrueInterest(_collateralToken); bytes32 key = _getPositionKey(_owner, _indexToken, _collateralToken, _side); Position memory position = positions[key]; if (position.size == 0) { revert PoolErrors.PositionNotExists(_owner, _indexToken, _collateralToken, _side); } DecreasePositionVars memory vars = _calcDecreasePayout( position, _indexToken, _collateralToken, _side, _sizeChanged, _collateralChanged, false ); vars.collateralReduced = position.collateralValue - vars.remainingCollateral; _releasePoolAsset(key, vars, _indexToken, _collateralToken, _side); position.size = position.size - vars.sizeChanged; position.borrowIndex = borrowIndex; position.reserveAmount = position.reserveAmount - vars.reserveReduced; position.collateralValue = vars.remainingCollateral; _validatePosition(position, _collateralToken, _side, vars.indexPrice); emit DecreasePosition( key, _owner, _collateralToken, _indexToken, vars.collateralReduced, vars.sizeChanged, _side, vars.indexPrice, vars.pnl.asTuple(), vars.feeValue ); if (position.size == 0) { emit ClosePosition( key, position.size, position.collateralValue, position.entryPrice, position.borrowIndex, position.reserveAmount ); delete positions[key]; } else { emit UpdatePosition( key, position.size, position.collateralValue, position.entryPrice, position.borrowIndex, position.reserveAmount, vars.indexPrice ); positions[key] = position; } _doTransferOut(_collateralToken, _receiver, vars.payout); if (address(poolHook) != address(0)) { poolHook.postDecreasePosition( _owner, _indexToken, _collateralToken, _side, abi.encode( vars.sizeChanged, vars.collateralReduced, vars.feeValue ) ); } } function liquidatePosition( address _account, address _indexToken, address _collateralToken, Side _side ) external { _requireValidTokenPair(_indexToken, _collateralToken, _side, false); uint256 borrowIndex = _accrueInterest(_collateralToken); bytes32 key = _getPositionKey(_account, _indexToken, _collateralToken, _side); Position memory position = positions[key]; uint256 markPrice = _getIndexPrice(_indexToken, _side, false); if (!_liquidatePositionAllowed(position, _side, markPrice, borrowIndex)) { revert PoolErrors.PositionNotLiquidated(key); } DecreasePositionVars memory vars = _calcDecreasePayout( position, _indexToken, _collateralToken, _side, position.size, position.collateralValue, true ); _releasePoolAsset(key, vars, _indexToken, _collateralToken, _side); emit LiquidatePosition( key, _account, _collateralToken, _indexToken, _side, position.size, position.collateralValue - vars.remainingCollateral, position.reserveAmount, vars.indexPrice, vars.pnl.asTuple(), vars.feeValue ); delete positions[key]; _doTransferOut(_collateralToken, _account, vars.payout); _doTransferOut( _collateralToken, msg.sender, fee.liquidationFee / vars.collateralPrice ); if (address(poolHook) != address(0)) { poolHook.postLiquidatePosition( _account, _indexToken, _collateralToken, _side, abi.encode(position.size, position.collateralValue, vars.feeValue) ); } } function refreshVirtualPoolValue() public { virtualPoolValue = (_getPoolValue(true) + _getPoolValue(false)) / 2; } // ========= ADMIN FUNCTIONS ======== function addTranche(address _tranche) external onlyOwner { require(_tranche != address(0), "Pool: invalid address"); require(!isTranche[_tranche], "Pool: already tranche"); isTranche[_tranche] = true; allTranches.push(_tranche); } // struct RiskConfig { // address tranche; // uint256 riskFactor; // } // function setRiskFactor( // address _token, // RiskConfig[] memory _config // ) external onlyOwner onlyAsset(_token) { // if (isStableCoin[_token]) { // revert PoolErrors.NotApplicableForStableCoin(); // } // uint256 total = totalRiskFactor[_token]; // for (uint256 i = 0; i < _config.length; ++i) { // (address tranche, uint256 factor) = ( // _config[i].tranche, // _config[i].riskFactor // ); // if (!isTranche[tranche]) { // revert PoolErrors.InvalidTranche(tranche); // } // total = total + factor - riskFactor[_token][tranche]; // riskFactor[_token][tranche] = factor; // } // totalRiskFactor[_token] = total; // emit TokenRiskFactorUpdated(_token); // } function addToken(address _token, bool _isStableCoin) external onlyOwner { if (!isAsset[_token]) { isAsset[_token] = true; isListed[_token] = true; allAssets.push(_token); isStableCoin[_token] = _isStableCoin; if (allAssets.length > MAX_ASSETS) { revert PoolErrors.TooManyTokenAdded( allAssets.length, MAX_ASSETS ); } emit TokenWhitelisted(_token); return; } if (isListed[_token]) { revert PoolErrors.DuplicateToken(_token); } isListed[_token] = true; emit TokenWhitelisted(_token); } // function delistToken(address _token) external onlyOwner { // if (!isListed[_token]) { // revert PoolErrors.AssetNotListed(_token); // } // isListed[_token] = false; // uint256 weight = targetWeights[_token]; // totalWeight -= weight; // targetWeights[_token] = 0; // emit TokenDelisted(_token); // } // function setMaintenanceMargin(uint256 _margin) external onlyOwner { // _setMaintenanceMargin(_margin); // } // function setMaxLiquidity(address _asset, uint256 _value) external onlyController onlyAsset(_asset) { // maxLiquidity[_asset] = _value; // emit MaxLiquiditySet(_asset, _value); // } // function setSwapFee( // uint256 _baseSwapFee, // uint256 _taxBasisPoint, // uint256 _stableCoinBaseSwapFee, // uint256 _stableCoinTaxBasisPoint // ) external onlyOwner { // _validateMaxValue(_baseSwapFee, MAX_BASE_SWAP_FEE); // _validateMaxValue(_stableCoinBaseSwapFee, MAX_BASE_SWAP_FEE); // _validateMaxValue(_taxBasisPoint, MAX_TAX_BASIS_POINT); // _validateMaxValue(_stableCoinTaxBasisPoint, MAX_TAX_BASIS_POINT); // fee.baseSwapFee = _baseSwapFee; // fee.taxBasisPoint = _taxBasisPoint; // fee.stableCoinBaseSwapFee = _stableCoinBaseSwapFee; // fee.stableCoinTaxBasisPoint = _stableCoinTaxBasisPoint; // emit SwapFeeSet( // _baseSwapFee, // _taxBasisPoint, // _stableCoinBaseSwapFee, // _stableCoinTaxBasisPoint // ); // } // function setPositionFee(uint256 _positionFee, uint256 _liquidationFee) external onlyOwner { // _setPositionFee(_positionFee, _liquidationFee); // } // function setAddRemoveLiquidityFee(uint256 _value) external onlyOwner { // _validateMaxValue(_value, MAX_BASE_SWAP_FEE); // addRemoveLiquidityFee = _value; // emit AddRemoveLiquidityFeeSet(_value); // } // function setDaoFee(uint256 _daoFee) external onlyOwner { // _validateMaxValue(_daoFee, PRECISION); // fee.daoFee = _daoFee; // emit DaoFeeSet(_daoFee); // } // function setInterestRate( // address[] calldata _assetAddress, // uint256[] calldata _interestRate, // uint256 _accrualInterval // ) external onlyOwner { // _setInterestRate(_assetAddress ,_interestRate, _accrualInterval); // } function setOrderManager(address _orderManager) external onlyOwner { _requireAddress(_orderManager); orderManager = _orderManager; emit SetOrderManager(_orderManager); } function withdrawFee( address _token, address _recipient ) external onlyAsset(_token) { if (msg.sender != feeDistributor) { revert PoolErrors.FeeDistributorOnly(); } uint256 amount = poolTokens[_token].feeReserve; poolTokens[_token].feeReserve = 0; _doTransferOut(_token, _recipient, amount); emit DaoFeeWithdrawn(_token, _recipient, amount); } function setFeeDistributor(address _feeDistributor) external onlyOwner { _requireAddress(_feeDistributor); feeDistributor = _feeDistributor; emit FeeDistributorSet(feeDistributor); } function setOracle(address _oracle) external onlyOwner { address oldOracle = address(oracle); oracle = IAipxOracle(_oracle); emit OracleChanged(oldOracle, _oracle); } // function setTargetWeight(TokenWeight[] memory tokens) external onlyOwner { // uint nTokens = tokens.length; // if (nTokens != allAssets.length) { // revert PoolErrors.RequireAllTokens(); // } // uint256 total; // for (uint256 i = 0; i < nTokens; ++i) { // TokenWeight memory item = tokens[i]; // assert(isAsset[item.token]); // // unlisted token always has zero weight // uint256 weight = isListed[item.token] ? item.weight : 0; // targetWeights[item.token] = weight; // total += weight; // } // totalWeight = total; // emit TokenWeightSet(tokens); // } // function setPoolHook(address _hook) external onlyOwner { // poolHook = IPoolHook(_hook); // emit PoolHookChanged(_hook); // } // function setMaxGlobalPositionSize(address _token, uint256 _maxGlobalLongRatio, uint256 _maxGlobalShortSize) // external // onlyController // onlyAsset(_token) // { // if (isStableCoin[_token]) { // revert PoolErrors.NotApplicableForStableCoin(); // } // _validateMaxValue(_maxGlobalLongRatio, PRECISION); // maxGlobalLongSizeRatios[_token] = _maxGlobalLongRatio; // maxGlobalShortSizes[_token] = _maxGlobalShortSize; // emit MaxGlobalPositionSizeSet(_token, _maxGlobalLongRatio, _maxGlobalShortSize); // } // function rebalanceAsset( // address _fromTranche, // address _fromToken, // uint256 _fromAmount, // address _toTranche, // address _toToken // ) external onlyController { // uint256 toAmount = MathUtils.frac(_fromAmount, _getPrice(_fromToken, true), _getPrice(_toToken, true)); // _decreaseTranchePoolAmount(_fromTranche, _fromToken, _fromAmount); // _decreaseTranchePoolAmount(_toTranche, _toToken, toAmount); // trancheAssets[_fromTranche][_toToken].poolAmount += toAmount; // trancheAssets[_toTranche][_fromToken].poolAmount += toAmount; // emit AssetRebalanced(); // } // ======== internal functions ========= function _setMaxLeverage(uint256 _maxLeverage) internal { if (_maxLeverage == 0) { revert PoolErrors.InvalidMaxLeverage(); } maxLeverage = _maxLeverage; emit MaxLeverageChanged(_maxLeverage); } function _setMaintenanceMargin(uint256 _ratio) internal { _validateMaxValue(_ratio, MAX_MAINTENANCE_MARGIN); maintenanceMargin = _ratio; emit MaintenanceMarginChanged(_ratio); } function _setInterestRate( address[] calldata _assetAddresses, uint256[] calldata _interestRate, uint256 _accrualInterval ) internal { if (_accrualInterval == 0) { revert PoolErrors.InvalidInterval(); } accrualInterval = _accrualInterval; for (uint256 i = 0; i < _assetAddresses.length; i++) { _validateMaxValue(_interestRate[i], MAX_INTEREST_RATE); assetInterestRate[_assetAddresses[i]] = _interestRate[i]; emit InterestRateSet(_assetAddresses[i], _interestRate[i], _accrualInterval); } } function _setPositionFee( uint256 _positionFee, uint256 _liquidationFee ) internal { _validateMaxValue(_positionFee, MAX_POSITION_FEE); _validateMaxValue(_liquidationFee, MAX_LIQUIDATION_FEE); fee.positionFee = _positionFee; fee.liquidationFee = _liquidationFee; emit PositionFeeSet(_positionFee, _liquidationFee); } function _validateToken( address _indexToken, address _collateralToken, Side _side, bool _isIncrease ) internal view returns (bool) { if (!isAsset[_indexToken] || !isAsset[_collateralToken]) { return false; } if (_isIncrease && (!isListed[_indexToken] || !isListed[_collateralToken])) { return false; } return _side == Side.LONG ? _indexToken == _collateralToken : isStableCoin[_collateralToken]; } function _calcAddLiquidity(address _tranche, address _token, uint256 _amountIn) internal view returns (uint256 amountInAfterFee, uint256 daoFee, uint256 lpAmount) { if (!isStableCoin[_token] && riskFactor[_token][_tranche] == 0) { revert PoolErrors.AddLiquidityNotAllowed(_tranche, _token); } uint256 tokenPrice = _getPrice(_token, false); uint256 valueChange = _amountIn * tokenPrice; uint256 _fee = _calcFeeRate( _token, tokenPrice, valueChange, addRemoveLiquidityFee, fee.taxBasisPoint, true ); uint256 userAmount = MathUtils.frac(_amountIn, PRECISION - _fee, PRECISION); (daoFee, ) = _calcDaoFee(_amountIn - userAmount); amountInAfterFee = _amountIn - daoFee; uint256 trancheValue = _getTrancheValue(_tranche, true); uint256 lpSupply = ILPToken(_tranche).totalSupply(); if (lpSupply == 0 || trancheValue == 0) { lpAmount = MathUtils.frac(userAmount, tokenPrice, LP_INITIAL_PRICE); } else { lpAmount = (userAmount * tokenPrice * lpSupply) / trancheValue; } } function _calcRemoveLiquidity(address _tranche, address _tokenOut, uint256 _lpAmount) internal view returns (uint256 outAmount, uint256 outAmountAfterFee, uint256 daoFee, uint256 tokenPrice) { tokenPrice = _getPrice(_tokenOut, true); uint256 poolValue = _getTrancheValue(_tranche, false); uint256 totalSupply = ILPToken(_tranche).totalSupply(); uint256 valueChange = (_lpAmount * poolValue) / totalSupply; uint256 _fee = _calcFeeRate( _tokenOut, tokenPrice, valueChange, addRemoveLiquidityFee, fee.taxBasisPoint, false ); outAmount = (_lpAmount * poolValue) / totalSupply / tokenPrice; outAmountAfterFee = MathUtils.frac(outAmount, PRECISION - _fee, PRECISION); (daoFee, ) = _calcDaoFee(outAmount - outAmountAfterFee); } function _calcSwapOutput(address _tokenIn, address _tokenOut, uint256 _amountIn) internal view returns (uint256 amountOutAfterFee, uint256 feeAmount) { uint256 priceIn = _getPrice(_tokenIn, false); uint256 priceOut = _getPrice(_tokenOut, true); uint256 valueChange = _amountIn * priceIn; bool isStableSwap = isStableCoin[_tokenIn] && isStableCoin[_tokenOut]; uint256 feeIn = _calcSwapFee(isStableSwap, _tokenIn, priceIn, valueChange, true); uint256 feeOut = _calcSwapFee(isStableSwap, _tokenOut, priceOut, valueChange, false); uint256 _fee = feeIn > feeOut ? feeIn : feeOut; amountOutAfterFee = (valueChange * (PRECISION - _fee)) / priceOut / PRECISION; feeAmount = (valueChange * _fee) / priceIn / PRECISION; } function _getPositionKey(address _owner, address _indexToken, address _collateralToken, Side _side) internal pure returns (bytes32) { return keccak256(abi.encode(_owner, _indexToken, _collateralToken, _side)); } function _validatePosition( Position memory _position, address _collateralToken, Side _side, uint256 _indexPrice ) internal view { if ((_position.size != 0 && _position.collateralValue == 0)) { revert PoolErrors.InvalidPositionSize(); } if (_position.size < _position.collateralValue) { revert PoolErrors.InvalidLeverage(_position.size, _position.collateralValue, maxLeverage); } uint256 borrowIndex = poolTokens[_collateralToken].borrowIndex; if (_liquidatePositionAllowed(_position, _side, _indexPrice, borrowIndex)) { revert PoolErrors.UpdateCauseLiquidation(); } } function _requireValidTokenPair( address _indexToken, address _collateralToken, Side _side, bool _isIncrease ) internal view { if (!_validateToken(_indexToken, _collateralToken, _side, _isIncrease)) { revert PoolErrors.InvalidTokenPair(_indexToken, _collateralToken); } } function _validateAsset(address _token) internal view { if (!isAsset[_token]) { revert PoolErrors.UnknownToken(_token); } } function _validateTranche(address _tranche) internal view { if (!isTranche[_tranche]) { revert PoolErrors.InvalidTranche(_tranche); } } function _requireAddress(address _address) internal pure { if (_address == address(0)) { revert PoolErrors.ZeroAddress(); } } // function _onlyController() internal view { // require(msg.sender == controller || msg.sender == owner(), "onlyController"); // } function _requireAmount(uint256 _amount) internal pure returns (uint256) { if (_amount == 0) { revert PoolErrors.ZeroAmount(); } return _amount; } function _requireListedToken(address _token) internal view { if (!isListed[_token]) { revert PoolErrors.AssetNotListed(_token); } } function _requireOrderManager() internal view { if (msg.sender != orderManager) { revert PoolErrors.OrderManagerOnly(); } } function _validateMaxValue(uint256 _input, uint256 _max) internal pure { if (_input > _max) { revert PoolErrors.ValueTooHigh(_max); } } function _getAmountIn(address _token) internal returns (uint256 amount) { uint256 balance = IERC20(_token).balanceOf(address(this)); amount = balance - poolTokens[_token].poolBalance; // 100 -30 = 70 poolTokens[_token].poolBalance = balance; // } function _doTransferOut(address _token, address _to, uint256 _amount) internal { if (_amount != 0) { IERC20 token = IERC20(_token); token.safeTransfer(_to, _amount); poolTokens[_token].poolBalance = token.balanceOf(address(this)); } } function _accrueInterest(address _token) internal returns (uint256) { PoolTokenInfo memory tokenInfo = poolTokens[_token]; AssetInfo memory asset = _getPoolAsset(_token); uint256 _now = block.timestamp; if (tokenInfo.lastAccrualTimestamp == 0 || asset.poolAmount == 0) { tokenInfo.lastAccrualTimestamp = (_now / accrualInterval) * accrualInterval; } else { uint256 nInterval = (_now - tokenInfo.lastAccrualTimestamp) / accrualInterval; if (nInterval == 0) { return tokenInfo.borrowIndex; } tokenInfo.borrowIndex += (nInterval * assetInterestRate[_token] * asset.reservedAmount) / asset.poolAmount; tokenInfo.lastAccrualTimestamp += nInterval * accrualInterval; } poolTokens[_token] = tokenInfo; emit InterestAccrued(_token, tokenInfo.borrowIndex); return tokenInfo.borrowIndex; } /// @notice calculate adjusted fee rate /// fee is increased or decreased based on action's effect to pool amount /// each token has their target weight set by gov /// if action make the weight of token far from its target, fee will be increase, vice versa function _calcSwapFee( bool _isStableSwap, address _token, uint256 _tokenPrice, uint256 _valueChange, bool _isSwapIn ) internal view returns (uint256) { (uint256 baseSwapFee, uint256 taxBasisPoint) = _isStableSwap ? (fee.stableCoinBaseSwapFee, fee.stableCoinTaxBasisPoint) : (fee.baseSwapFee, fee.taxBasisPoint); return _calcFeeRate(_token, _tokenPrice, _valueChange, baseSwapFee, taxBasisPoint, _isSwapIn); } function _calcFeeRate( address _token, uint256 _tokenPrice, uint256 _valueChange, uint256 _baseFee, uint256 _taxBasisPoint, bool _isIncrease ) internal view returns (uint256) { uint256 _targetValue = totalWeight == 0 ? 0 : (targetWeights[_token] * virtualPoolValue) / totalWeight; if (_targetValue == 0) { return _baseFee; } uint256 _currentValue = _tokenPrice * _getPoolAsset(_token).poolAmount; uint256 _nextValue = _isIncrease ? _currentValue + _valueChange : _currentValue - _valueChange; uint256 initDiff = MathUtils.diff(_currentValue, _targetValue); uint256 nextDiff = MathUtils.diff(_nextValue, _targetValue); if (nextDiff < initDiff) { uint256 feeAdjust = (_taxBasisPoint * initDiff) / _targetValue; uint rate = MathUtils.zeroCapSub(_baseFee, feeAdjust); return rate > MIN_SWAP_FEE ? rate : MIN_SWAP_FEE; } else { uint256 avgDiff = (initDiff + nextDiff) / 2; uint256 feeAdjust = avgDiff > _targetValue ? _taxBasisPoint : (_taxBasisPoint * avgDiff) / _targetValue; return _baseFee + feeAdjust; } } function _getPoolValue(bool _max) internal view returns (uint256 sum) { uint256[] memory prices = _getAllPrices(_max); for (uint256 i = 0; i < allTranches.length; ) { sum += _getTrancheValue(allTranches[i], prices); unchecked { ++i; } } } function _getAllPrices(bool _max) internal view returns (uint256[] memory) { return oracle.getMultiplePrices(allAssets, _max); } function _getTrancheValue( address _tranche, bool _max ) internal view returns (uint256 sum) { return _getTrancheValue(_tranche, _getAllPrices(_max)); } function _getTrancheValue( address _tranche, uint256[] memory prices ) internal view returns (uint256 sum) { int256 aum; for (uint256 i = 0; i < allAssets.length; ) { address token = allAssets[i]; assert(isAsset[token]); // double check AssetInfo memory asset = trancheAssets[_tranche][token]; uint256 price = prices[i]; if (isStableCoin[token]) { aum = aum + (price * asset.poolAmount).toInt256(); } else { uint256 averageShortPrice = averageShortPrices[_tranche][token]; int256 shortPnl = PositionUtils.calcPnl( Side.SHORT, asset.totalShortSize, averageShortPrice, price ); aum = aum + ((asset.poolAmount - asset.reservedAmount) * price + asset.guaranteedValue).toInt256() - shortPnl; } unchecked { ++i; } } // aum MUST not be negative. If it is, please debug return aum.toUint256(); } function _decreaseTranchePoolAmount( address _tranche, address _token, uint256 _amount ) internal { AssetInfo memory asset = trancheAssets[_tranche][_token]; asset.poolAmount -= _amount; if (asset.poolAmount < asset.reservedAmount) { revert PoolErrors.InsufficientPoolAmount(_token); } trancheAssets[_tranche][_token] = asset; } /// @notice return pseudo pool asset by sum all tranches asset function _getPoolAsset( address _token ) internal view returns (AssetInfo memory asset) { for (uint256 i = 0; i < allTranches.length; ) { address tranche = allTranches[i]; asset.poolAmount += trancheAssets[tranche][_token].poolAmount; asset.reservedAmount += trancheAssets[tranche][_token].reservedAmount; asset.totalShortSize += trancheAssets[tranche][_token].totalShortSize; asset.guaranteedValue += trancheAssets[tranche][_token].guaranteedValue; unchecked { ++i; } } } /// @notice reserve asset when open position function _reservePoolAsset( bytes32 _key, IncreasePositionVars memory _vars, address _indexToken, address _collateralToken, Side _side ) internal { AssetInfo memory collateral = _getPoolAsset(_collateralToken); uint256 maxReserve = collateral.poolAmount; if (_vars.sizeChanged > 0) { if (_side == Side.LONG) { uint256 maxReserveRatio = maxGlobalLongSizeRatios[_indexToken]; if (maxReserveRatio != 0) { maxReserve = MathUtils.frac(maxReserve, maxReserveRatio, PRECISION); } } else { uint256 maxGlobalShortSize = maxGlobalShortSizes[_indexToken]; uint256 globalShortSize = collateral.totalShortSize + _vars.sizeChanged; if (maxGlobalShortSize != 0 && maxGlobalShortSize < globalShortSize) { revert PoolErrors.MaxGlobalShortSizeExceeded(_indexToken, globalShortSize); } } } if (collateral.reservedAmount + _vars.reserveAdded > maxReserve) { revert PoolErrors.InsufficientPoolAmount(_collateralToken); } poolTokens[_collateralToken].feeReserve += _vars.daoFee; _reserveTrancheAsset(_key, _vars, _indexToken, _collateralToken, _side); } /// @notice release asset and take or distribute realized PnL when close position function _releasePoolAsset( bytes32 _key, DecreasePositionVars memory _vars, address _indexToken, address _collateralToken, Side _side ) internal { AssetInfo memory collateral = _getPoolAsset(_collateralToken); if (collateral.reservedAmount < _vars.reserveReduced) { revert PoolErrors.ReserveReduceTooMuch(_collateralToken); } poolTokens[_collateralToken].feeReserve += _vars.daoFee; _releaseTranchesAsset(_key, _vars, _indexToken, _collateralToken, _side); } function _reserveTrancheAsset( bytes32 _key, IncreasePositionVars memory _vars, address _indexToken, address _collateralToken, Side _side ) internal { uint256[] memory shares; uint256 totalShare; if (_vars.reserveAdded != 0) { totalShare = _vars.reserveAdded; shares = _calcTrancheSharesAmount( _indexToken, _collateralToken, totalShare, false ); } else { totalShare = _vars.collateralAmount; shares = _calcTrancheSharesAmount( _indexToken, _collateralToken, totalShare, true ); } for (uint256 i = 0; i < shares.length; ) { address tranche = allTranches[i]; uint256 share = shares[i]; AssetInfo memory collateral = trancheAssets[tranche][ _collateralToken ]; uint256 reserveAmount = MathUtils.frac( _vars.reserveAdded, share, totalShare ); tranchePositionReserves[tranche][_key] += reserveAmount; collateral.reservedAmount += reserveAmount; collateral.poolAmount += MathUtils.frac( _vars.totalLpFee, riskFactor[_indexToken][tranche], totalRiskFactor[_indexToken] ); if (_side == Side.LONG) { collateral.poolAmount = MathUtils.addThenSubWithFraction( collateral.poolAmount, _vars.collateralAmount, _vars.feeAmount, share, totalShare ); // ajust guaranteed // guaranteed value = total(size - (collateral - fee)) // delta_guaranteed value = sizechange + fee - collateral collateral.guaranteedValue = MathUtils.addThenSubWithFraction( collateral.guaranteedValue, _vars.sizeChanged + _vars.feeValue, _vars.collateralValueAdded, share, totalShare ); } else { uint256 sizeChanged = MathUtils.frac(_vars.sizeChanged, share, totalShare); uint256 indexPrice = _vars.indexPrice; _updateGlobalShortPrice(tranche, _indexToken, sizeChanged, true, indexPrice, 0); } trancheAssets[tranche][_collateralToken] = collateral; unchecked { ++i; } } } function _releaseTranchesAsset( bytes32 _key, DecreasePositionVars memory _vars, address _indexToken, address _collateralToken, Side _side ) internal { uint256 totalShare = positions[_key].reserveAmount; for (uint256 i = 0; i < allTranches.length; ) { address tranche = allTranches[i]; uint256 share = tranchePositionReserves[tranche][_key]; AssetInfo memory collateral = trancheAssets[tranche][ _collateralToken ]; { uint256 reserveReduced = MathUtils.frac( _vars.reserveReduced, share, totalShare ); tranchePositionReserves[tranche][_key] -= reserveReduced; collateral.reservedAmount -= reserveReduced; } uint256 lpFee = MathUtils.frac( _vars.totalLpFee, riskFactor[_indexToken][tranche], totalRiskFactor[_indexToken] ); collateral.poolAmount = ((collateral.poolAmount + lpFee) .toInt256() - _vars.poolAmountReduced.frac(share, totalShare)) .toUint256(); if (collateral.poolAmount < collateral.reservedAmount) { revert PoolErrors.InsufficientPoolAmount(_collateralToken); } int256 pnl = _vars.pnl.frac(share, totalShare); if (_side == Side.LONG) { collateral.guaranteedValue = MathUtils.addThenSubWithFraction( collateral.guaranteedValue, _vars.collateralReduced, _vars.sizeChanged, share, totalShare); } else { uint256 sizeChanged = MathUtils.frac(_vars.sizeChanged, share, totalShare); uint256 indexPrice = _vars.indexPrice; _updateGlobalShortPrice(tranche, _indexToken, sizeChanged, false, indexPrice, pnl); } trancheAssets[tranche][_collateralToken] = collateral; emit PnLDistributed(_collateralToken, tranche, pnl.abs(), pnl >= 0); unchecked { ++i; } } } /// @notice distributed amount of token to all tranches /// @param _indexToken the token of which risk factors is used to calculate ratio /// @param _collateralToken pool amount or reserve of this token will be changed. So we must cap the amount to be changed to the /// max available value of this token (pool amount - reserve) when _isIncreasePoolAmount set to false /// @param _isIncreasePoolAmount set to true when "increase pool amount" or "decrease reserve amount" function _calcTrancheSharesAmount( address _indexToken, address _collateralToken, uint256 _amount, bool _isIncreasePoolAmount ) internal view returns (uint256[] memory reserves) { uint256 nTranches = allTranches.length; //3 reserves = new uint256[](nTranches); uint256[] memory factors = new uint256[](nTranches); uint256[] memory maxShare = new uint256[](nTranches); for (uint256 i = 0; i < nTranches; ) { address tranche = allTranches[i]; AssetInfo memory asset = trancheAssets[tranche][_collateralToken]; factors[i] = isStableCoin[_indexToken] ? 1 : riskFactor[_indexToken][tranche]; maxShare[i] = _isIncreasePoolAmount ? type(uint256).max : asset.poolAmount - asset.reservedAmount; unchecked { ++i; } } uint256 totalFactor = isStableCoin[_indexToken] ? nTranches : totalRiskFactor[_indexToken]; for (uint256 k = 0; k < nTranches; ) { unchecked { ++k; } uint256 totalRiskFactor_ = totalFactor; for (uint256 i = 0; i < nTranches; ) { uint256 riskFactor_ = factors[i]; if (riskFactor_ != 0) { uint256 shareAmount = MathUtils.frac(_amount, riskFactor_, totalRiskFactor_); uint256 availableAmount = maxShare[i] - reserves[i]; if (shareAmount >= availableAmount) { // skip this tranche on next rounds since it's full shareAmount = availableAmount; totalFactor -= riskFactor_; factors[i] = 0; } reserves[i] += shareAmount; _amount -= shareAmount; totalRiskFactor_ -= riskFactor_; if (_amount == 0) { return reserves; } } unchecked { ++i; } } } revert PoolErrors.CannotDistributeToTranches( _indexToken, _collateralToken, _amount, _isIncreasePoolAmount ); } /// @notice rebalance fund between tranches after swap token function _rebalanceTranches( address _tokenIn, uint256 _amountInAfterFee, address _tokenOut, uint256 _amountOut, uint256 _lpFee ) internal { uint256[] memory outAmounts; uint256[] memory lpFeeAmounts; address indexToken = isStableCoin[_tokenIn] && !isStableCoin[_tokenOut] ? _tokenOut : _tokenIn; outAmounts = _calcTrancheSharesAmount(indexToken, _tokenOut, _amountOut, false); lpFeeAmounts = _calcTrancheSharesAmount(indexToken, _tokenIn, _lpFee, true); for (uint256 i = 0; i < allTranches.length; ) { address tranche = allTranches[i]; trancheAssets[tranche][_tokenOut].poolAmount -= outAmounts[i]; trancheAssets[tranche][_tokenIn].poolAmount += MathUtils.frac(_amountInAfterFee, outAmounts[i], _amountOut) + lpFeeAmounts[i]; unchecked { ++i; } } } function _liquidatePositionAllowed( Position memory _position, Side _side, uint256 _indexPrice, uint256 _borrowIndex ) internal view returns (bool allowed) { if (_position.size == 0) { return false; } uint256 feeValue = _calcPositionFee(_position, _position.size, _borrowIndex); int256 pnl = PositionUtils.calcPnl(_side, _position.size, _position.entryPrice, _indexPrice); int256 collateral = pnl + _position.collateralValue.toInt256(); // liquidation occur when collateral cannot cover margin fee or lower than maintenance margin return collateral < 0 || uint256(collateral) * PRECISION < _position.size * maintenanceMargin || uint256(collateral) < (feeValue + fee.liquidationFee); } function _calcDecreasePayout( Position memory _position, address _indexToken, address _collateralToken, Side _side, uint256 _sizeChanged, uint256 _collateralChanged, bool isLiquidate ) internal view returns (DecreasePositionVars memory vars) { // clean user input vars.sizeChanged = MathUtils.min(_position.size, _sizeChanged); vars.collateralReduced = _position.collateralValue < _collateralChanged || _position.size == vars.sizeChanged ? _position.collateralValue : _collateralChanged; vars.indexPrice = _getIndexPrice(_indexToken, _side, false); vars.collateralPrice = _getCollateralPrice(_collateralToken, false); // vars is santinized, only trust these value from now on vars.reserveReduced = (_position.reserveAmount * vars.sizeChanged) / _position.size; vars.pnl = PositionUtils.calcPnl(_side, vars.sizeChanged, _position.entryPrice, vars.indexPrice); vars.feeValue = _calcPositionFee(_position, vars.sizeChanged, poolTokens[_collateralToken].borrowIndex); // first try to deduct fee and lost (if any) from withdrawn collateral int256 payoutValue = vars.pnl + vars.collateralReduced.toInt256() - vars.feeValue.toInt256(); if (isLiquidate) { payoutValue = payoutValue - fee.liquidationFee.toInt256(); } int256 remainingCollateral = (_position.collateralValue - vars.collateralReduced).toInt256(); // subtraction never overflow, checked above // if the deduction is too much, try to deduct from remaining collateral if (payoutValue < 0) { remainingCollateral = remainingCollateral + payoutValue; payoutValue = 0; } int256 collateralPrice = vars.collateralPrice.toInt256(); vars.payout = uint256(payoutValue / collateralPrice); int256 poolValueReduced = vars.pnl; if (remainingCollateral < 0) { if (!isLiquidate) { revert PoolErrors.UpdateCauseLiquidation(); } // if liquidate too slow, pool must take the lost poolValueReduced = poolValueReduced - remainingCollateral; vars.remainingCollateral = 0; } else { vars.remainingCollateral = uint256(remainingCollateral); } if (_side == Side.LONG) { poolValueReduced = poolValueReduced + vars.collateralReduced.toInt256(); } else if (poolValueReduced < 0) { // in case of SHORT, trader can lost unlimited value but pool can only increase at most collateralValue - liquidationFee poolValueReduced = poolValueReduced.cap( MathUtils.zeroCapSub(_position.collateralValue, vars.feeValue + fee.liquidationFee) ); } vars.poolAmountReduced = poolValueReduced / collateralPrice; (vars.daoFee, vars.totalLpFee) = _calcDaoFee(vars.feeValue / vars.collateralPrice); } function _calcPositionFee(Position memory _position, uint256 _sizeChanged, uint256 _borrowIndex) internal view returns (uint256 feeValue) { // fee = borrowFee + positionFee uint256 borrowFee = ((_borrowIndex - _position.borrowIndex) * _position.size) / PRECISION; uint256 positionFee = (_sizeChanged * fee.positionFee) / PRECISION; feeValue = borrowFee + positionFee; } function _getIndexPrice(address _token, Side _side, bool _isIncrease) internal view returns (uint256) { // max == (_isIncrease & _side = LONG) | (!_increase & _side = SHORT) // max = _isIncrease == (_side == Side.LONG); return _getPrice(_token, _isIncrease == (_side == Side.LONG)); } function _getCollateralPrice(address _token, bool _isIncrease) internal view returns (uint256) { return (isStableCoin[_token]) // force collateral price = 1 incase of using stablecoin as collateral ? 10 ** (USD_VALUE_DECIMAL - IERC20Metadata(_token).decimals()) : _getPrice(_token, !_isIncrease); } function _getPrice(address _token, bool _max) internal view returns (uint256) { return oracle.getPrice(_token, _max); } function _validateMaxLiquidity(address _token) internal view { uint256 max = maxLiquidity[_token]; if (max == 0){ return; } uint256 poolAmount = _getPoolAsset(_token).poolAmount; if (max < poolAmount) { revert PoolErrors.MaxLiquidityReach(); } } function _updateGlobalShortPrice( address _tranche, address _indexToken, uint256 _sizeChanged, bool _isIncrease, uint256 _indexPrice, int256 _realizedPnl ) internal { uint256 lastSize = trancheAssets[_tranche][_indexToken].totalShortSize; uint256 nextSize = _isIncrease ? lastSize + _sizeChanged : MathUtils.zeroCapSub(lastSize, _sizeChanged); uint256 entryPrice = averageShortPrices[_tranche][_indexToken]; uint256 shortPrice = PositionUtils.calcAveragePrice( Side.SHORT, lastSize, nextSize, entryPrice, _indexPrice, _realizedPnl ); averageShortPrices[_tranche][_indexToken] = shortPrice; trancheAssets[_tranche][_indexToken].totalShortSize = nextSize; } function _calcDaoFee( uint256 _feeAmount ) internal view returns (uint256 daoFee, uint256 lpFee) { daoFee = MathUtils.frac(_feeAmount, fee.daoFee, PRECISION); lpFee = _feeAmount - daoFee; } }
@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
@openzeppelin/contracts/utils/Address.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
@openzeppelin/contracts/utils/math/SafeCast.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.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 SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @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 * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(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 * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(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 * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(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 * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "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 * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "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. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @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 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @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 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @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 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @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 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @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 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
contracts/interfaces/IAipxOracle.sol
//SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.0; interface IAipxOracle { function getPrice(address token, bool max) external view returns (uint256); function getMultiplePrices( address[] calldata tokens, bool max ) external view returns (uint256[] memory); }
contracts/interfaces/ILPToken.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.15; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface ILPToken is IERC20 { function mint(address to, uint amount) external; function burnFrom(address account, uint256 amount) external; }
@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
@openzeppelin/contracts/interfaces/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
@openzeppelin/contracts/interfaces/IERC20Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../token/ERC20/extensions/IERC20Metadata.sol";
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
contracts/interfaces/IPool.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.15; import {SignedInt} from "../lib/SignedInt.sol"; enum Side { LONG, SHORT } struct TokenWeight { address token; uint256 weight; } interface IPool { function increasePosition( address _account, address _indexToken, address _collateralToken, uint256 _sizeChanged, Side _side ) external; function decreasePosition( address _account, address _indexToken, address _collateralToken, uint256 _desiredCollateralReduce, uint256 _sizeChanged, Side _side, address _receiver ) external; function liquidatePosition(address _account, address _indexToken, address _collateralToken, Side _side) external; function validateToken(address indexToken, address collateralToken, Side side, bool isIncrease) external view returns (bool); function swap(address _tokenIn, address _tokenOut, uint256 _minOut, address _to, bytes calldata extradata) external; function addLiquidity(address _tranche, address _token, uint256 _amountIn, uint256 _minLpAmount, address _to) external; function removeLiquidity(address _tranche, address _tokenOut, uint256 _lpAmount, uint256 _minOut, address _to) external; // =========== EVENTS =========== event SetOrderManager(address indexed orderManager); event IncreasePosition( bytes32 indexed key, address account, address collateralToken, address indexToken, uint256 collateralValue, uint256 sizeChanged, Side side, uint256 indexPrice, uint256 feeValue ); event UpdatePosition( bytes32 indexed key, uint256 size, uint256 collateralValue, uint256 entryPrice, uint256 entryInterestRate, uint256 reserveAmount, uint256 indexPrice ); event DecreasePosition( bytes32 indexed key, address account, address collateralToken, address indexToken, uint256 collateralChanged, uint256 sizeChanged, Side side, uint256 indexPrice, SignedInt pnl, uint256 feeValue ); event ClosePosition( bytes32 indexed key, uint256 size, uint256 collateralValue, uint256 entryPrice, uint256 entryInterestRate, uint256 reserveAmount ); event LiquidatePosition( bytes32 indexed key, address account, address collateralToken, address indexToken, Side side, uint256 size, uint256 collateralValue, uint256 reserveAmount, uint256 indexPrice, SignedInt pnl, uint256 feeValue ); event DaoFeeWithdrawn(address indexed token, address recipient, uint256 amount); event DaoFeeReduced(address indexed token, uint256 amount); event FeeDistributorSet(address indexed feeDistributor); event LiquidityAdded( address indexed tranche, address indexed sender, address token, uint256 amount, uint256 lpAmount, uint256 fee ); event LiquidityRemoved( address indexed tranche, address indexed sender, address token, uint256 lpAmount, uint256 amountOut, uint256 fee ); event TokenWeightSet(TokenWeight[]); event Swap( address indexed sender, address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOut, uint256 fee ); event PositionFeeSet(uint256 positionFee, uint256 liquidationFee); event DaoFeeSet(uint256 value); event SwapFeeSet( uint256 baseSwapFee, uint256 taxBasisPoint, uint256 stableCoinBaseSwapFee, uint256 stableCoinTaxBasisPoint ); event InterestAccrued(address indexed token, uint256 borrowIndex); event MaxLeverageChanged(uint256 maxLeverage); event TokenWhitelisted(address indexed token); event TokenDelisted(address indexed token); event OracleChanged(address indexed oldOracle, address indexed newOracle); event InterestRateSet(address token, uint256 interestRate, uint256 interval); event PoolHookChanged(address indexed hook); event TrancheAdded(address indexed lpToken); event TokenRiskFactorUpdated(address indexed token); event PnLDistributed(address indexed asset, address indexed tranche, uint256 amount, bool hasProfit); event MaintenanceMarginChanged(uint256 ratio); event AddRemoveLiquidityFeeSet(uint256 value); event MaxGlobalPositionSizeSet(address indexed token, uint256 maxLongRatios, uint256 maxShortSize); event PoolControllerChanged(address controller); event AssetRebalanced(); event MaxLiquiditySet(address token, uint256 maxLiquidity); }
contracts/interfaces/IPoolHook.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.15; import {Side, IPool} from "./IPool.sol"; interface IPoolHook { function postIncreasePosition( address owner, address indexToken, address collateralToken, Side side, bytes calldata extradata ) external; function postDecreasePosition( address owner, address indexToken, address collateralToken, Side side, bytes calldata extradata ) external; function postLiquidatePosition( address owner, address indexToken, address collateralToken, Side side, bytes calldata extradata ) external; function postSwap(address user, address tokenIn, address tokenOut, bytes calldata data) external; event PreIncreasePositionExecuted( address pool, address owner, address indexToken, address collateralToken, Side side, bytes extradata ); event PostIncreasePositionExecuted( address pool, address owner, address indexToken, address collateralToken, Side side, bytes extradata ); event PreDecreasePositionExecuted( address pool, address owner, address indexToken, address collateralToken, Side side, bytes extradata ); event PostDecreasePositionExecuted( address pool, address owner, address indexToken, address collateralToken, Side side, bytes extradata ); event PreLiquidatePositionExecuted( address pool, address owner, address indexToken, address collateralToken, Side side, bytes extradata ); event PostLiquidatePositionExecuted( address pool, address owner, address indexToken, address collateralToken, Side side, bytes extradata ); event PostSwapExecuted(address pool, address user, address tokenIn, address tokenOut, bytes data); }
contracts/lib/MathUtils.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; library MathUtils { function diff(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a - b : b - a; } function zeroCapSub(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a - b : 0; } function frac(uint256 amount, uint256 num, uint256 denom) internal pure returns (uint256) { return amount * num / denom; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } function addThenSubWithFraction(uint256 orig, uint256 add, uint256 sub, uint256 num, uint256 denum) internal pure returns (uint256) { return zeroCapSub(orig + MathUtils.frac(add, num, denum), MathUtils.frac(sub, num, denum)); } }
contracts/lib/PositionUtils.sol
// SPDX-License-Identifier: UNLCIENSED pragma solidity >=0.8.0; import {Side} from "../interfaces/IPool.sol"; import {SignedInt, SignedIntOps} from "./SignedInt.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; library PositionUtils { using SafeCast for uint256; using SignedIntOps for int256; function calcPnl(Side _side, uint256 _positionSize, uint256 _entryPrice, uint256 _indexPrice) internal pure returns (int256) { if (_positionSize == 0 || _entryPrice == 0) { return 0; } int256 entryPrice = _entryPrice.toInt256(); int256 positionSize = _positionSize.toInt256(); int256 indexPrice = _indexPrice.toInt256(); if (_side == Side.LONG) { return (indexPrice - entryPrice) * positionSize / entryPrice; } else { return (entryPrice - indexPrice) * positionSize / entryPrice; } } /// @notice calculate new avg entry price when increase position /// @dev for longs: nextAveragePrice = (nextPrice * nextSize)/ (nextSize + delta) /// for shorts: nextAveragePrice = (nextPrice * nextSize) / (nextSize - delta) function calcAveragePrice( Side _side, uint256 _lastSize, uint256 _nextSize, uint256 _entryPrice, uint256 _nextPrice, int256 _realizedPnL ) internal pure returns (uint256) { if (_nextSize == 0) { return 0; } if (_lastSize == 0) { return _nextPrice; } int256 pnl = calcPnl(_side, _lastSize, _entryPrice, _nextPrice) - _realizedPnL; int256 nextSize = _nextSize.toInt256(); int256 divisor = _side == Side.LONG ? nextSize + pnl : nextSize - pnl; return divisor <= 0 ? 0 : _nextSize * _nextPrice / uint256(divisor); } }
contracts/lib/SignedInt.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.0; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; uint256 constant POS = 1; uint256 constant NEG = 0; /// SignedInt is integer number with sign. It value range is -(2 ^ 256 - 1) to (2 ^ 256 - 1) struct SignedInt { /// @dev sig = 1 -> positive, sig = 0 is negative /// using uint256 which take up full word to optimize gas and contract size uint256 sig; uint256 abs; } library SignedIntOps { using SafeCast for uint256; function frac(int256 a, uint256 num, uint256 denom) internal pure returns (int256) { return a * num.toInt256() / denom.toInt256(); } function abs(int256 x) internal pure returns (uint256) { return x < 0 ? uint256(-x) : uint256(x); } function asTuple(int256 x) internal pure returns (SignedInt memory) { return SignedInt({abs: abs(x), sig: x < 0 ? NEG : POS}); } function cap(int256 x, uint256 maxAbs) internal pure returns (int256) { int256 min = -maxAbs.toInt256(); return x > min ? x : min; } }
contracts/pool/PoolErrors.sol
// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.19; import {Side} from "../interfaces/IPool.sol"; library PoolErrors { error UpdateCauseLiquidation(); error InvalidTokenPair(address index, address collateral); error InvalidLeverage(uint256 size, uint256 margin, uint256 maxLeverage); error InvalidPositionSize(); error OrderManagerOnly(); error UnknownToken(address token); error AssetNotListed(address token); error InsufficientPoolAmount(address token); error ReserveReduceTooMuch(address token); error SlippageExceeded(); error ValueTooHigh(uint256 maxValue); error InvalidInterval(); error PositionNotLiquidated(bytes32 key); error ZeroAmount(); error ZeroAddress(); error RequireAllTokens(); error DuplicateToken(address token); error FeeDistributorOnly(); error InvalidMaxLeverage(); error SameTokenSwap(address token); error InvalidTranche(address tranche); error TrancheAlreadyAdded(address tranche); error RemoveLiquidityTooMuch(address tranche, uint256 outAmount, uint256 trancheBalance); error CannotDistributeToTranches( address indexToken, address collateralToken, uint256 amount, bool CannotDistributeToTranches ); error CannotSetRiskFactorForStableCoin(address token); error PositionNotExists(address owner, address indexToken, address collateralToken, Side side); error MaxNumberOfTranchesReached(); error TooManyTokenAdded(uint256 number, uint256 max); error AddLiquidityNotAllowed(address tranche, address token); error MaxGlobalShortSizeExceeded(address token, uint256 globalShortSize); error NotApplicableForStableCoin(); error MaxLiquidityReach(); }
contracts/pool/PoolStorage.sol
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import {IAipxOracle} from "../interfaces/IAipxOracle.sol"; import {ILPToken} from "../interfaces/ILPToken.sol"; import {IPoolHook} from "../interfaces/IPoolHook.sol"; // common precision for fee, tax, interest rate, maintenace margin ratio uint256 constant PRECISION = 1e10; uint256 constant LP_INITIAL_PRICE = 1e12; // fix to 1$ uint256 constant MAX_BASE_SWAP_FEE = 1e8; // 1% uint256 constant MAX_TAX_BASIS_POINT = 1e8; // 1% uint256 constant MAX_POSITION_FEE = 1e8; // 1% uint256 constant MAX_LIQUIDATION_FEE = 10e30; // 10$ uint256 constant MAX_TRANCHES = 3; uint256 constant MAX_ASSETS = 10; uint256 constant MAX_INTEREST_RATE = 1e7; // 0.1% uint256 constant MAX_MAINTENANCE_MARGIN = 5e8; // 5% struct Fee { /// @notice charge when changing position size uint256 positionFee; /// @notice charge when liquidate position (in dollar) uint256 liquidationFee; /// @notice swap fee used when add/remove liquidity, swap token uint256 baseSwapFee; /// @notice tax used to adjust swapFee due to the effect of the action on token's weight /// It reduce swap fee when user add some amount of a under weight token to the pool uint256 taxBasisPoint; /// @notice swap fee used when add/remove liquidity, swap token uint256 stableCoinBaseSwapFee; /// @notice tax used to adjust swapFee due to the effect of the action on token's weight /// It reduce swap fee when user add some amount of a under weight token to the pool uint256 stableCoinTaxBasisPoint; /// @notice part of fee will be kept for DAO, the rest will be distributed to pool amount, thus /// increase the pool value and the price of LP token uint256 daoFee; } struct Position { /// @dev contract size is evaluated in dollar uint256 size; /// @dev collateral value in dollar uint256 collateralValue; /// @dev contract size in indexToken uint256 reserveAmount; /// @dev average entry price uint256 entryPrice; /// @dev last cumulative interest rate uint256 borrowIndex; } struct PoolTokenInfo { /// @notice amount reserved for fee uint256 feeReserve; /// @notice recorded balance of token in pool uint256 poolBalance; /// @notice last borrow index update timestamp uint256 lastAccrualTimestamp; /// @notice accumulated interest rate uint256 borrowIndex; /// @notice average entry price of all short position /// @deprecated avg short price must be calculate per tranche uint256 ___averageShortPrice; } struct AssetInfo { /// @notice amount of token deposited (via add liquidity or increase long position) uint256 poolAmount; /// @notice amount of token reserved for paying out when user decrease long position uint256 reservedAmount; /// @notice total borrowed (in USD) to leverage uint256 guaranteedValue; /// @notice total size of all short positions uint256 totalShortSize; } abstract contract PoolStorage { Fee public fee; address public feeDistributor; IAipxOracle public oracle; address public orderManager; // ========= Assets management ========= mapping(address => bool) public isAsset; /// @notice A list of all configured assets /// @dev use a pseudo address for ETH /// Note that token will not be removed from this array when it was delisted. We keep this /// list to calculate pool value properly address[] public allAssets; mapping(address => bool) public isListed; mapping(address => bool) public isStableCoin; mapping(address => PoolTokenInfo) public poolTokens; /// @notice target weight for each tokens mapping(address => uint256) public targetWeights; mapping(address => bool) public isTranche; /// @notice risk factor of each token in each tranche /// @dev token => tranche => risk factor mapping(address => mapping(address => uint256)) public riskFactor; /// @dev token => total risk score mapping(address => uint256) public totalRiskFactor; address[] public allTranches; /// @dev tranche => token => asset info mapping(address => mapping(address => AssetInfo)) public trancheAssets; /// @notice position reserve in each tranche mapping(address => mapping(bytes32 => uint256)) public tranchePositionReserves; /// @notice interest rate for each asset mapping(address => uint256) public assetInterestRate; uint256 public accrualInterval; uint256 public totalWeight; // ========= Positions management ========= /// @notice max leverage for each token uint256 public maxLeverage; /// @notice positions tracks all open positions mapping(bytes32 => Position) public positions; IPoolHook public poolHook; uint256 public maintenanceMargin; uint256 public addRemoveLiquidityFee; mapping(address => mapping(address => uint256)) public averageShortPrices; /// @notice cached pool value for faster computation uint256 public virtualPoolValue; /// @notice index token => max global short size mapping(address => uint256) public maxGlobalShortSizes; mapping(address => uint256) public maxGlobalLongSizeRatios; address public controller; mapping(address => uint256) public maxLiquidity; }
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":true},"libraries":{}}
Contract ABI
[{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accrualInterval","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addLiquidity","inputs":[{"type":"address","name":"_tranche","internalType":"address"},{"type":"address","name":"_token","internalType":"address"},{"type":"uint256","name":"_amountIn","internalType":"uint256"},{"type":"uint256","name":"_minLpAmount","internalType":"uint256"},{"type":"address","name":"_to","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"addRemoveLiquidityFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addToken","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"bool","name":"_isStableCoin","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addTranche","inputs":[{"type":"address","name":"_tranche","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"allAssets","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"allTranches","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"assetInterestRate","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"averageShortPrices","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"controller","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"decreasePosition","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"uint256","name":"_collateralChanged","internalType":"uint256"},{"type":"uint256","name":"_sizeChanged","internalType":"uint256"},{"type":"uint8","name":"_side","internalType":"enum Side"},{"type":"address","name":"_receiver","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"positionFee","internalType":"uint256"},{"type":"uint256","name":"liquidationFee","internalType":"uint256"},{"type":"uint256","name":"baseSwapFee","internalType":"uint256"},{"type":"uint256","name":"taxBasisPoint","internalType":"uint256"},{"type":"uint256","name":"stableCoinBaseSwapFee","internalType":"uint256"},{"type":"uint256","name":"stableCoinTaxBasisPoint","internalType":"uint256"},{"type":"uint256","name":"daoFee","internalType":"uint256"}],"name":"fee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"feeDistributor","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAllTranchesLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct AssetInfo","components":[{"type":"uint256"},{"type":"uint256"},{"type":"uint256"},{"type":"uint256"}]}],"name":"getPoolAsset","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getPoolValue","inputs":[{"type":"bool","name":"_max","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"sum","internalType":"uint256"}],"name":"getTrancheValue","inputs":[{"type":"address","name":"_tranche","internalType":"address"},{"type":"bool","name":"_max","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"increasePosition","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"uint256","name":"_sizeChanged","internalType":"uint256"},{"type":"uint8","name":"_side","internalType":"enum Side"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"uint256","name":"_maxLeverage","internalType":"uint256"},{"type":"uint256","name":"_positionFee","internalType":"uint256"},{"type":"uint256","name":"_liquidationFee","internalType":"uint256"},{"type":"uint256","name":"_maintainanceMargin","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isAsset","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isListed","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isStableCoin","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTranche","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"liquidatePosition","inputs":[{"type":"address","name":"_account","internalType":"address"},{"type":"address","name":"_indexToken","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"uint8","name":"_side","internalType":"enum Side"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maintenanceMargin","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxGlobalLongSizeRatios","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxGlobalShortSizes","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxLeverage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maxLiquidity","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IAipxOracle"}],"name":"oracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"orderManager","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPoolHook"}],"name":"poolHook","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"feeReserve","internalType":"uint256"},{"type":"uint256","name":"poolBalance","internalType":"uint256"},{"type":"uint256","name":"lastAccrualTimestamp","internalType":"uint256"},{"type":"uint256","name":"borrowIndex","internalType":"uint256"},{"type":"uint256","name":"___averageShortPrice","internalType":"uint256"}],"name":"poolTokens","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"collateralValue","internalType":"uint256"},{"type":"uint256","name":"reserveAmount","internalType":"uint256"},{"type":"uint256","name":"entryPrice","internalType":"uint256"},{"type":"uint256","name":"borrowIndex","internalType":"uint256"}],"name":"positions","inputs":[{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"refreshVirtualPoolValue","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeLiquidity","inputs":[{"type":"address","name":"_tranche","internalType":"address"},{"type":"address","name":"_tokenOut","internalType":"address"},{"type":"uint256","name":"_lpAmount","internalType":"uint256"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"address","name":"_to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"riskFactor","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeDistributor","inputs":[{"type":"address","name":"_feeDistributor","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOracle","inputs":[{"type":"address","name":"_oracle","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOrderManager","inputs":[{"type":"address","name":"_orderManager","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"swap","inputs":[{"type":"address","name":"_tokenIn","internalType":"address"},{"type":"address","name":"_tokenOut","internalType":"address"},{"type":"uint256","name":"_minOut","internalType":"uint256"},{"type":"address","name":"_to","internalType":"address"},{"type":"bytes","name":"extradata","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"targetWeights","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalRiskFactor","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalWeight","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"poolAmount","internalType":"uint256"},{"type":"uint256","name":"reservedAmount","internalType":"uint256"},{"type":"uint256","name":"guaranteedValue","internalType":"uint256"},{"type":"uint256","name":"totalShortSize","internalType":"uint256"}],"name":"trancheAssets","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tranchePositionReserves","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"bytes32","name":"","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"validateToken","inputs":[{"type":"address","name":"_indexToken","internalType":"address"},{"type":"address","name":"_collateralToken","internalType":"address"},{"type":"uint8","name":"_side","internalType":"enum Side"},{"type":"bool","name":"_isIncrease","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"virtualPoolValue","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawFee","inputs":[{"type":"address","name":"_token","internalType":"address"},{"type":"address","name":"_recipient","internalType":"address"}]},{"type":"event","name":"AddRemoveLiquidityFeeSet","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"AssetRebalanced","inputs":[],"anonymous":false},{"type":"event","name":"ClosePosition","inputs":[{"type":"bytes32","name":"key","indexed":true},{"type":"uint256","name":"size","indexed":false},{"type":"uint256","name":"collateralValue","indexed":false},{"type":"uint256","name":"entryPrice","indexed":false},{"type":"uint256","name":"entryInterestRate","indexed":false},{"type":"uint256","name":"reserveAmount","indexed":false}],"anonymous":false},{"type":"event","name":"DaoFeeReduced","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"DaoFeeSet","inputs":[{"type":"uint256","name":"value","indexed":false}],"anonymous":false},{"type":"event","name":"DaoFeeWithdrawn","inputs":[{"type":"address","name":"token","indexed":true},{"type":"address","name":"recipient","indexed":false},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"DecreasePosition","inputs":[{"type":"bytes32","name":"key","indexed":true},{"type":"address","name":"account","indexed":false},{"type":"address","name":"collateralToken","indexed":false},{"type":"address","name":"indexToken","indexed":false},{"type":"uint256","name":"collateralChanged","indexed":false},{"type":"uint256","name":"sizeChanged","indexed":false},{"type":"uint8","name":"side","indexed":false},{"type":"uint256","name":"indexPrice","indexed":false},{"type":"tuple","name":"pnl","indexed":false,"components":[{"type":"uint256"},{"type":"uint256"}]},{"type":"uint256","name":"feeValue","indexed":false}],"anonymous":false},{"type":"event","name":"FeeDistributorSet","inputs":[{"type":"address","name":"feeDistributor","indexed":true}],"anonymous":false},{"type":"event","name":"IncreasePosition","inputs":[{"type":"bytes32","name":"key","indexed":true},{"type":"address","name":"account","indexed":false},{"type":"address","name":"collateralToken","indexed":false},{"type":"address","name":"indexToken","indexed":false},{"type":"uint256","name":"collateralValue","indexed":false},{"type":"uint256","name":"sizeChanged","indexed":false},{"type":"uint8","name":"side","indexed":false},{"type":"uint256","name":"indexPrice","indexed":false},{"type":"uint256","name":"feeValue","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","indexed":false}],"anonymous":false},{"type":"event","name":"InterestAccrued","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"borrowIndex","indexed":false}],"anonymous":false},{"type":"event","name":"InterestRateSet","inputs":[{"type":"address","name":"token","indexed":false},{"type":"uint256","name":"interestRate","indexed":false},{"type":"uint256","name":"interval","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidatePosition","inputs":[{"type":"bytes32","name":"key","indexed":true},{"type":"address","name":"account","indexed":false},{"type":"address","name":"collateralToken","indexed":false},{"type":"address","name":"indexToken","indexed":false},{"type":"uint8","name":"side","indexed":false},{"type":"uint256","name":"size","indexed":false},{"type":"uint256","name":"collateralValue","indexed":false},{"type":"uint256","name":"reserveAmount","indexed":false},{"type":"uint256","name":"indexPrice","indexed":false},{"type":"tuple","name":"pnl","indexed":false,"components":[{"type":"uint256"},{"type":"uint256"}]},{"type":"uint256","name":"feeValue","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidityAdded","inputs":[{"type":"address","name":"tranche","indexed":true},{"type":"address","name":"sender","indexed":true},{"type":"address","name":"token","indexed":false},{"type":"uint256","name":"amount","indexed":false},{"type":"uint256","name":"lpAmount","indexed":false},{"type":"uint256","name":"fee","indexed":false}],"anonymous":false},{"type":"event","name":"LiquidityRemoved","inputs":[{"type":"address","name":"tranche","indexed":true},{"type":"address","name":"sender","indexed":true},{"type":"address","name":"token","indexed":false},{"type":"uint256","name":"lpAmount","indexed":false},{"type":"uint256","name":"amountOut","indexed":false},{"type":"uint256","name":"fee","indexed":false}],"anonymous":false},{"type":"event","name":"MaintenanceMarginChanged","inputs":[{"type":"uint256","name":"ratio","indexed":false}],"anonymous":false},{"type":"event","name":"MaxGlobalPositionSizeSet","inputs":[{"type":"address","name":"token","indexed":true},{"type":"uint256","name":"maxLongRatios","indexed":false},{"type":"uint256","name":"maxShortSize","indexed":false}],"anonymous":false},{"type":"event","name":"MaxLeverageChanged","inputs":[{"type":"uint256","name":"maxLeverage","indexed":false}],"anonymous":false},{"type":"event","name":"MaxLiquiditySet","inputs":[{"type":"address","name":"token","indexed":false},{"type":"uint256","name":"maxLiquidity","indexed":false}],"anonymous":false},{"type":"event","name":"OracleChanged","inputs":[{"type":"address","name":"oldOracle","indexed":true},{"type":"address","name":"newOracle","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false},{"type":"event","name":"PnLDistributed","inputs":[{"type":"address","name":"asset","indexed":true},{"type":"address","name":"tranche","indexed":true},{"type":"uint256","name":"amount","indexed":false},{"type":"bool","name":"hasProfit","indexed":false}],"anonymous":false},{"type":"event","name":"PoolControllerChanged","inputs":[{"type":"address","name":"controller","indexed":false}],"anonymous":false},{"type":"event","name":"PoolHookChanged","inputs":[{"type":"address","name":"hook","indexed":true}],"anonymous":false},{"type":"event","name":"PositionFeeSet","inputs":[{"type":"uint256","name":"positionFee","indexed":false},{"type":"uint256","name":"liquidationFee","indexed":false}],"anonymous":false},{"type":"event","name":"SetOrderManager","inputs":[{"type":"address","name":"orderManager","indexed":true}],"anonymous":false},{"type":"event","name":"Swap","inputs":[{"type":"address","name":"sender","indexed":true},{"type":"address","name":"tokenIn","indexed":false},{"type":"address","name":"tokenOut","indexed":false},{"type":"uint256","name":"amountIn","indexed":false},{"type":"uint256","name":"amountOut","indexed":false},{"type":"uint256","name":"fee","indexed":false}],"anonymous":false},{"type":"event","name":"SwapFeeSet","inputs":[{"type":"uint256","name":"baseSwapFee","indexed":false},{"type":"uint256","name":"taxBasisPoint","indexed":false},{"type":"uint256","name":"stableCoinBaseSwapFee","indexed":false},{"type":"uint256","name":"stableCoinTaxBasisPoint","indexed":false}],"anonymous":false},{"type":"event","name":"TokenDelisted","inputs":[{"type":"address","name":"token","indexed":true}],"anonymous":false},{"type":"event","name":"TokenRiskFactorUpdated","inputs":[{"type":"address","name":"token","indexed":true}],"anonymous":false},{"type":"event","name":"TokenWeightSet","inputs":[{"type":"tuple[]","name":"","indexed":false,"components":[{"type":"address"},{"type":"uint256"}]}],"anonymous":false},{"type":"event","name":"TokenWhitelisted","inputs":[{"type":"address","name":"token","indexed":true}],"anonymous":false},{"type":"event","name":"TrancheAdded","inputs":[{"type":"address","name":"lpToken","indexed":true}],"anonymous":false},{"type":"event","name":"UpdatePosition","inputs":[{"type":"bytes32","name":"key","indexed":true},{"type":"uint256","name":"size","indexed":false},{"type":"uint256","name":"collateralValue","indexed":false},{"type":"uint256","name":"entryPrice","indexed":false},{"type":"uint256","name":"entryInterestRate","indexed":false},{"type":"uint256","name":"reserveAmount","indexed":false},{"type":"uint256","name":"indexPrice","indexed":false}],"anonymous":false},{"type":"error","name":"AddLiquidityNotAllowed","inputs":[{"type":"address","name":"tranche","internalType":"address"},{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"AssetNotListed","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"CannotDistributeToTranches","inputs":[{"type":"address","name":"indexToken","internalType":"address"},{"type":"address","name":"collateralToken","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bool","name":"CannotDistributeToTranches","internalType":"bool"}]},{"type":"error","name":"DuplicateToken","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"FeeDistributorOnly","inputs":[]},{"type":"error","name":"InsufficientPoolAmount","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"InvalidLeverage","inputs":[{"type":"uint256","name":"size","internalType":"uint256"},{"type":"uint256","name":"margin","internalType":"uint256"},{"type":"uint256","name":"maxLeverage","internalType":"uint256"}]},{"type":"error","name":"InvalidMaxLeverage","inputs":[]},{"type":"error","name":"InvalidPositionSize","inputs":[]},{"type":"error","name":"InvalidTokenPair","inputs":[{"type":"address","name":"index","internalType":"address"},{"type":"address","name":"collateral","internalType":"address"}]},{"type":"error","name":"InvalidTranche","inputs":[{"type":"address","name":"tranche","internalType":"address"}]},{"type":"error","name":"MaxGlobalShortSizeExceeded","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"globalShortSize","internalType":"uint256"}]},{"type":"error","name":"MaxLiquidityReach","inputs":[]},{"type":"error","name":"OrderManagerOnly","inputs":[]},{"type":"error","name":"PositionNotExists","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"indexToken","internalType":"address"},{"type":"address","name":"collateralToken","internalType":"address"},{"type":"uint8","name":"side","internalType":"enum Side"}]},{"type":"error","name":"PositionNotLiquidated","inputs":[{"type":"bytes32","name":"key","internalType":"bytes32"}]},{"type":"error","name":"ReserveReduceTooMuch","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"SameTokenSwap","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"SlippageExceeded","inputs":[]},{"type":"error","name":"TooManyTokenAdded","inputs":[{"type":"uint256","name":"number","internalType":"uint256"},{"type":"uint256","name":"max","internalType":"uint256"}]},{"type":"error","name":"UnknownToken","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"error","name":"UpdateCauseLiquidation","inputs":[]},{"type":"error","name":"ValueTooHigh","inputs":[{"type":"uint256","name":"maxValue","internalType":"uint256"}]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"error","name":"ZeroAmount","inputs":[]}]
Contract Creation Code
0x6080806040523461001757615ce090816200001d8239f35b600080fdfe610160604052600436101561001357600080fd5b60006101405260003560e01c8063069d0254146137215780630a51f5f0146136e35780630d43e8ad146136b757806313a8b3e51461363d57806322c53fa51461361c5780632388dac1146132275780633545c789146131fb5780633e9ee375146131a6578063415f6820146131575780634b086657146131025780634b2fc7bb14612c34578063514ea4bf14612bc857806355a0c97114612b85578063578e5c2214612b5c5780635d8048db1461204557806360a2da4414611dd85780636c3e737914611db75780637127346414611d96578063715018a614611d315780637adbf97314611cc45780637dc0d1d014611c985780637e865aa4146117585780638da5cb5b1461172c5780639698d25a146116ee57806396c82e57146116cd5780639790576a1461168a578063a186159a1461164c578063a4f845dc14611607578063a912616914611589578063ab5770d314610f2e578063ae3302c214610f0d578063b45e670a14610ecf578063bab3e9e614610e55578063bc97c95e14610e17578063c0da840d14610da2578063c790281814610d4c578063c879c6d814610c8f578063c87fa42a14610c4c578063cb2d23ba14610c30578063ccfc2e8d14610bb4578063d0616ea814610a83578063d5eb058114610a62578063db38342314610a20578063ddc88817146109ff578063ddca3f43146109ab578063ef8250101461096d578063f2fde38b146108e0578063f6252c71146108ae578063f77c479114610882578063f794062e1461083f578063f9b6117f146108135763faf920121461025f57600080fd5b3461072357608036600319011261072357610278613774565b61028061378a565b6102886137a0565b9160026064351015610723576102a1606435848461457a565b156107e5576102af8361498b565b6102bd606435858585614647565b9182610140515260b16020526102f36102db60406101405120613cc7565b926102ea606435151587615bfc565b606435856159a4565b156107cc578151926104ec602084015160009060405196610313886139c6565b6000885260006020890152600060408901526000606089015260006080890152600060a0890152600060c0890152600060e089015260006101008901526000610120890152600061014089015260006101608901528651908082106000146107c45750905b8160208901526020870151918183109081156107b9575b50156107b257505b86526103a7606435151588615bfc565b60408701526103b588615a73565b60608701526103d86103d06040870151602089015190613cb4565b865190613d13565b60a08701526103f860208701516060870151604089015191606435613f9a565b610120870152610427602087015160018060a01b038a1660005260a56020526003604060002001549087615a38565b60c087015261045b6104486101208801516104428951613ea7565b90613db3565b61045560c0890151613ea7565b90613d9a565b61046b6098549161045583613ea7565b9161048461047f60208901518a5190613ca7565b613ea7565b6000841261079e575b6104a461049d60608b0151613ea7565b8095613f31565b6101008a015261012089015191600082121561079157506104c790600092613d9a565b91600060808a01525b60643561072a5750506104e7906104428851613ea7565b613f31565b61014085015261050560c0850151606086015190613d13565b6105226402540be40061051a609d5484613cb4565b048092613ca7565b61016086015260e085015261053c60643587878785615069565b807f8b372416ec9524b0238c4da0dc9f7d743dae07b6391152c6b768877d68c080b061016084896020898b8a5161057b848d0151608085015190613ca7565b60408d01519160408501519360c0610597610120880151614028565b960151604080516001600160a01b039b8c168152998b16898b015291909916908801529596956105cc60608901606435613d33565b608088015260a087015260c086015260e085015280516101008501520151610120830152610140820152a2610140515260b16020526106296040610140512060046000918281558260018201558260028201558260038201550155565b61063961010084015182876148cb565b61065461064d609854606086015190613d13565b33876148cb565b60b2546001600160a01b0316918261066e575b6101405180f35b806106a160c060206106af9451930151960151604051968793602085016040919493926060820195825260208201520152565b03601f1981018552846139e2565b813b15610723576106e094604051958694859384936388a494ff60e01b855261014051986064359260048701613d56565b039161014051905af18015610715576106fe575b8080808080610667565b61070790613998565b6101405180156106f4575b80fd5b6040513d61014051823e3d90fd5b6101405180fd5b818312610739575b5050613f31565b61074c60208901519160c08b0151613a28565b808211156107835761047f6107649161076993613ca7565b614082565b90508082131561077c57505b3880610732565b9050610775565b505061076961076482613ea7565b91929060808a01526104d0565b926107a99193613db3565b9160009261048d565b9050610397565b90508751143861038f565b905090610378565b60405163be12177560e01b815260048101849052602490fd5b5060405163ec998d1d60e01b81526001600160a01b03918216600482015291166024820152604490fd5b0390fd5b346107235761014051806003193601126107125760a0546040516001600160a01b039091168152602090f35b34610723576020366003190112610723576001600160a01b03610860613774565b16610140515260a3602052602060ff6040610140512054166040519015158152f35b346107235761014051806003193601126107125760b9546040516001600160a01b039091168152602090f35b34610723576040366003190112610723576106676108ca613774565b6108d261386d565b906108db61387c565b614369565b34610723576020366003190112610723576108f9613774565b61090161387c565b6001600160a01b0381161561091957610667906138d4565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b34610723576020366003190112610723576001600160a01b0361098e613774565b16610140515260ad60205260206040610140512054604051908152f35b346107235761014051806003193601126107125760e0609754609854609954609a54609b5490609c5492609d5494604051968752602087015260408601526060850152608084015260a083015260c0820152f35b3461072357610140518060031936011261071257602060b454604051908152f35b346107235760203660031901126107235760043560aa5481101561072357610a49602091613836565b905460405160039290921b1c6001600160a01b03168152f35b3461072357610140518060031936011261071257602060b354604051908152f35b3461072357602036600319011261072357610a9c613774565b610aa461387c565b6001600160a01b039081168015610b775780610140515260a760205260ff604061014051205416610b3a5780610140515260a760205260406101405120600160ff1982541617905560aa54600160401b811015610b2457806001610b0b920160aa55613836565b909283549160031b92831b921b19161790556101405180f35b634e487b7160e01b600052604160045260246000fd5b60405162461bcd60e51b8152602060048201526015602482015274506f6f6c3a20616c7265616479207472616e63686560581b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274506f6f6c3a20696e76616c6964206164647265737360581b6044820152606490fd5b3461072357602036600319011261072357610bcd613774565b610bd561387c565b610bde81614796565b60018060a01b0316609e5490806bffffffffffffffffffffffff60a01b831617609e5561014051809216177fc567a7e76455af13dfa1d15455b235923c14ccb050c95473d8341b6bafcc1a538280a280f35b3461072357610140518060031936011261071257610667614093565b34610723576020366003190112610723576001600160a01b03610c6d613774565b16610140515260a1602052602060ff6040610140512054166040519015158152f35b3461072357604036600319011261072357610ca8613774565b610cb061378a565b90610cba81614720565b609e546001600160a01b03919082163303610d3a577f6f8fef25a3cd63e7d1cae44c5eeaad06db500709a24fab9630fcc59d7b22642b9181169283610140515260a5602052610d1861014051928260408520918254958693556148cb565b604080516001600160a01b039290921682526020820192909252a26101405180f35b60405163a4cdd60360e01b8152600490fd5b3461072357608036600319011261072357610d65613774565b610d6d61378a565b90604435600281101561072357606435908115158203610d9d57602093610d93936145b7565b6040519015158152f35b600080fd5b3461072357602036600319011261072357610dbb613774565b610dc361387c565b610dcc81614796565b60a080546001600160a01b0319166001600160a01b0392909216918217905561014051907f3ca8ff425d27ae390700aab4fc3bd68ad54292e65f04097717a261f0c633acc88280a280f35b34610723576020366003190112610723576001600160a01b03610e38613774565b16610140515260a660205260206040610140512054604051908152f35b34610723576020366003190112610723576004358015158103610d9d57610e7d600091614c80565b60aa54600092915b818410610e9757602083604051908152f35b9091610ec5600191610ebf84610eac88613836565b868060a01b0391549060031b1c16614dd3565b90613a28565b9301929190610e85565b34610723576020366003190112610723576001600160a01b03610ef0613774565b16610140515260ba60205260206040610140512054604051908152f35b3461072357610140518060031936011261071257602060b054604051908152f35b346107235760e036600319011261072357610f47613774565b610f4f61378a565b610f576137a0565b91600260a43510156107235760c4356001600160a01b0381169003610d9d57610f7e61480e565b610f8b60a435848461457a565b156107e557610f998361498b565b90610fa860a435858584614647565b80610140515260b1602052610fc260406101405120613cc7565b8051156115655760405193610fd6856139c6565b6000855260006020860152600060408601526000606086015260006080860152600060a0860152600060c0860152600060e08601526000610100860152600061012086015260006101408601526000610160860152815160843580821060001461155e57505b80602087015260208301519060643590818310908115611553575b501561154c57505b855261106f60a435151587615bfc565b604086015261107d87615a73565b60608601526110a06110986040840151602088015190613cb4565b835190613d13565b60a08601526110c06020860151606084015160408801519160a435613f9a565b6101208601526110ef602086015160018060a01b03891660005260a56020526003604060002001549084615a38565b60c086015261111761110a6101208701516104428851613ea7565b61045560c0880151613ea7565b61112a61047f6020850151885190613ca7565b906000811261153c575b61114b6111446060890151613ea7565b8092613f31565b610100880152610120870151600083121561117257604051636108ecc160e01b8152600490fd5b61119492608089015260a435156000146114e1576104e7906104428951613ea7565b6101408601526111ad60c0860151606087015190613d13565b6111c26402540be40061051a609d5484613cb4565b61016087015260e08601526111e06020830151608087015190613ca7565b85526111f160a43588888887615069565b6112018251602087015190613ca7565b8252608082015261121b604082015160a086015190613ca7565b60408201526080840151602082015261123c604085015160a4358884614675565b817fcd04eb76238d1d18dc5b134bd1a2fc71184aedd9b40ee1970faef50d860d141261014085896020898b8151838301519060408401519260c0611284610120870151614028565b950151604080516001600160a01b039a8b168152988a16888a01529190981690870152606086015260808501529293926112c360a0860160a435613d33565b60c0850152805160e08501520151610100830152610120820152a280518061143557508051602080830151606080850151608080870151604097880151885197885295870194909452958501528301529181019190915281907f57646b4faf64a91c1ad76512fe716b11edf1056115e03bd65877e0640570ffb59060a090a2610140515260b16020526113746040610140512060046000918281558260018201558260028201558260038201550155565b61138661010083015160c435866148cb565b60b2546001600160a01b0316908161139f576101405180f35b6113d160208401516106a160c08651960151604051968793602085016040919493926060820195825260208201520152565b813b1561072357611402946040519586948593849363fd19608d60e01b8552610140519860a4359260048701613d56565b039161014051905af180156107155761141f575b80808080610667565b61142890613998565b6101405180156114165780fd5b6020828101516060808501516080808701516040808901518c8201518251998a52978901969096528701929092529185015283015260a08201526114dc929081907f569f4ef16f93b9d0b6625dcd44e8eb6e6ca8db330ee738654cd9fd57461499c79060c090a2610140515260b160205260406101405120906080600491805184556020810151600185015560408101516002850155606081015160038501550151910155565b611374565b6000811215613f3157602085015161150060c08a015160985490613a28565b8082111561152d5761047f6107649161151893613ca7565b808213156115265750613f31565b9050613f31565b50506115186107646000613ea7565b61154591613db3565b6000611134565b905061105f565b90508451148a611057565b905061103c565b505060405163c00d27c360e01b815293849361080f935060a4359260048601613ff6565b34610723576020366003190112610723576001600160a01b036115aa613774565b16610140515260a56020526040610140512080546116036001830154926002810154906004600382015491015491604051958695869192608093969594919660a084019784526020840152604083015260608201520152565b0390f35b34610723576040366003190112610723576020611644611625613774565b61163e61163061386d565b6116398361475b565b614c80565b90614dd3565b604051908152f35b34610723576020366003190112610723576001600160a01b0361166d613774565b16610140515260a960205260206040610140512054604051908152f35b34610723576020366003190112610723576001600160a01b036116ab613774565b16610140515260a7602052602060ff6040610140512054166040519015158152f35b3461072357610140518060031936011261071257602060af54604051908152f35b34610723576020366003190112610723576001600160a01b0361170f613774565b16610140515260b760205260206040610140512054604051908152f35b34610723576101405180600319360112610712576033546040516001600160a01b039091168152602090f35b346107235760a036600319011261072357611771613774565b61177961378a565b906064356001600160a01b0381169003610d9d576001600160401b038060843511610723573660236084350112156107235760843560040135116107235736602460843560040135608435010111610723576117d3613a35565b6117dc816147d3565b6117e582614720565b6001600160a01b0381811690831614611c76576118018161498b565b5061180b8261498b565b5061181d61181882614834565b6147b8565b9061182781615bb5565b9061183184615b40565b9161183c8185613cb4565b9260018060a01b038316610140515260a4602052610140519060ff6040832054169182611c56575b508115611c475761187e609b54609c54905b878688614be8565b9115611c3857611897609b54609c54905b87848b614aef565b61014051929080821115611c305750915b826402540be40003906402540be4008211611c1857506118e7926402540be4006118e08196946118db6118db958b613cb4565b613d13565b0496613cb4565b04926044358310611c06576402540be400611904609d5486613cb4565b04926119108486613ca7565b9360018060a01b038416610140515260a560205261193660406101405120918254613a28565b90556119428583613ca7565b61014080516001600160a01b038616905260a460205251604081205460ff169081611be6575b5015611bdc5761198687955b85611980858b8a61578a565b97615545565b92610140515b60aa54811015611a535780878a611a1d611a0c886118db611a05876119b260019a613836565b8b8060a01b0391549060031b1c16976119cb8282614dbf565b5189610140515260ab988960205260406101405120908d8060a01b03166000526020526119fe6040600020918254613ca7565b9055614dbf565b518a613cb4565b611a16858b614dbf565b5190613a28565b91610140515260205260406101405120838060a01b038916600052602052611a4b6040600020918254613a28565b90550161198c565b888287868b611a6183615c43565b611a6e82606435876148cb565b604080516001600160a01b03858116825287166020820152908101859052606081018390526080810182905233907fd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf77604139060a090a260b2546001600160a01b03169182611ae1575b60016065556101405180f35b604051946020860152604085015260608401526080808401526084356004013560a08401526084356004013560246084350160c08501376101405160c06084356004013585010152611b4d60c084601f19601f60843560040135011681010360a08101865201846139e2565b803b1561072357604051638857560b60e01b81526001600160a01b0360648035821660048401529381166024830152949094166044850152608091840191909152610140519183919082908190611ba8906084830190613c67565b039161014051905af1801561071557611bc6575b8080808080611ad5565b611bcf90613998565b610140518015611bbc5780fd5b6119868495611974565b6001600160a01b03891690525061014051604090205460ff161588611968565b604051638199f5f360e01b8152600490fd5b634e487b7160e01b9052601160045261014051602490fd5b9050916118a8565b611897609954609a549061188f565b61187e609954609a5490611876565b6001600160a01b038816905261014051604090205460ff16915087611864565b6040516369ed396360e01b81526001600160a01b039091166004820152602490fd5b3461072357610140518060031936011261071257609f546040516001600160a01b039091168152602090f35b3461072357602036600319011261072357611cdd613774565b611ce561387c565b609f80546001600160a01b039283166001600160a01b0319821681179092556101405192167f05cd89403c6bdeac21c2ff33de395121a31fa1bc2bf3adf4825f1f86e79969dd8380a380f35b3461072357610140518060031936011261071257611d4d61387c565b603380546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36101405180f35b3461072357610140518060031936011261071257602060aa54604051908152f35b3461072357610140518060031936011261071257602060ae54604051908152f35b3461072357608036600319011261072357600435602435604435906064359061014051549260ff8460081c161593848095612038575b8015612021575b15611fc55760ff611e4891610140519087600184198316178355611fb4575b505460081c16611e438161391d565b61391d565b611e51336138d4565b610140515494611e6a60ff8760081c16611e438161391d565b60016065558015611fa2576020817f629b53ebf66271b592438aa954e367dad37de9cd1c1a2b9dc4acade7e1ff9f409260b055604051908152a16305f5e100808311611f8a57506c7e37be2022c0914b2680000000808211611f8a5750816040917f1c22ce892d949604d8532ddac8cca2e0199a1168487d121893beb4d2739700f9936097558060985582519182526020820152a1631dcd6500808211611f8a57506020817f361f687df539664645c65434f6ac8ca100a42a2411ee76fac9e2fbeeb07f33509260b355604051908152a16402540be400609d55611f4f576101405180f35b61ff00191661014051557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a180610667565b60249060405190630a253bc760e41b82526004820152fd5b604051633af35be560e11b8152600490fd5b61ffff191661010117815588611e34565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015611e155750600160ff821614611e15565b50600160ff821610611e0e565b346107235760a03660031901126107235761205e613774565b61206661378a565b9061206f6137a0565b60c052600260843510156107235761208561480e565b61209460843560c051846144c6565b15612b3157604051806101205261012081018181106001600160401b03821117610b24576040526101405190526101405160206101205101526101405160406101205101526101405160606101205101526101405160806101205101526101405160a06101205101526101405160c06101205101526101405160e06101205101526101405161010061012051015261213061181860c051614834565b602061012051015260c05160018060a01b03811660005260a460205260ff60406000205416600014612b22575060405163313ce56760e01b815260c051602090829060049082906001600160a01b03165afa908115612b1657600091612ada575b50601e60ff8216810311612ac457604d60ff8216601e0311612ac45760ff16601e03600a0a915b6121c9602061012051015184613cb4565b60406101205101526121dc60c05161498b565b6121ec60843560c0518486614647565b8060a052610140515260b160205261220960406101405120613cc7565b6080526122926000946122226084351560011485615bfc565b60a061012051015260643560c06101205101526122568161224885606435608051615a38565b806060610120510152613d13565b8060e06101205101526122746402540be40061051a609d5484613cb4565b610100610120510152608061012051015260c0610120510151613d13565b61012051526122c8608051516122af60c061012051015182613a28565b606060805101519060a061012051015192608435613dcf565b606060805101526122e760206080510151604061012051015190613a28565b6101205160600151610140519181811115612abd576123069250613ca7565b602060805101526123226080515160c061012051015190613a28565b60805152608080510152612340610120515160406080510151613a28565b6040608051015260c0610120510151151580612aa0575b612a6b5761237460a061012051015160843560c051608051614675565b61237f60c051614f7a565b80519060c061012051015161298c575b6020015161012051516123a191613a28565b1161296957608061012051015160018060a01b0360c05116610140515260a56020526123d560406101405120918254613a28565b905561014051610100526101205180511561294f575061012051516123fd8160c0518461578a565b610100525b610140515b610100515181101561272f5761241c81613836565b9190549161242d8261010051614dbf565b519260018060a01b03818360031b1c16610140515260ab6020526040610140512060018060a01b0360c05116600052602052600360406000206124756040518060e05261397d565b805460e051526001810154602060e05101526002810154604060e05101520154606060e05101526124fa6124b1866118db876101205151613cb4565b60018060a01b03838560031b1c16610140515260ac60205261014051604081209060a0519052602052604061014051206124ec828254613a28565b9055602060e0510151613a28565b602060e05101528761257161256861010061012051015160018060a01b038a16610140515260a86020526118db610140516040812060018060a01b03888a60031b1c166000526020526040600020549060018060a01b038d16905260a9602052604061014051205492613cb4565b60e05151613a28565b60e05152612715576001938560843561263857816125a5826125d59460e051516101205160e06020820151910151916154d7565b60e05152604060e05101516125c761012051606060c082015191015190613a28565b6040610120510151916154d7565b604060e05101525b838060a01b039160031b1c16610140515260ab60205260406101405120828060a01b0360c0511660005260205260406000206003606060e0518051845560208101518685015560408101516002850155015191015501612407565b6118db61264c9260c0610120510151613cb4565b60a061012051015190858060a01b03838560031b1c1660005260ab6020526040600020868060a01b0389166000526020526126cb6126936003604060002001549283613a28565b92878060a01b03858760031b1c1660005260b592836020526040600020898060a01b038c166000526020528460406000205491613e49565b600385811b85901c60a089901b899003908116600081815260209586526040808220938e168083529387528082209590955590815260ab85528381209181529352912001556125dd565b634e487b7160e01b61014051526021600452602461014051fd5b828460a051610140515260b160205261277a60805160406101405120906080600491805184556020810151600185015560408101516002850155606081015160038501550151910155565b6101006101205160208101519060c081015190606060a0820151910151916040519360018060a01b038716855260018060a01b0360c05116602086015260018060a01b0388166040860152606085015260808401526127de60a08401608435613d33565b60c083015260e08201527f8f1a004341b7c2e1e0799b80c6b849e04431c20757ba9b8c9064d5132405465d60a051928392a27f569f4ef16f93b9d0b6625dcd44e8eb6e6ca8db330ee738654cd9fd57461499c76080518051612888602083015192606081015190604060808201519101519060a061012051015192604051968796879260a094919796959260c0850198855260208501526040840152606083015260808201520152565b0390a260b2546001600160a01b0316806128a3576101405180f35b61012051906128ea60606040840151930151926128dc604051948592606435602085016040919493926060820195825260208201520152565b03601f1981018452836139e2565b803b156107235761291e936040518095819482936305c317db60e01b845261014051976084359160c0519160048701613d56565b039161014051905af1801561071557612939575b8080610667565b61294290613998565b6101405180156129325780fd5b602001516129608160c05184615545565b61010052612402565b60405163503e811160e11b815260c0516001600160a01b03166004820152602490fd5b600094506084356129e85761014080516001600160a01b038516905260b8602052516040902054806129c9575b5060206123a1915b91505061238f565b6402540be4006129df6020926123a19495613cb4565b049291506129b9565b61014080516001600160a01b038516905260b760205251604090205460608201516101205160c00151612a1a91613a28565b90818115159182612a61575b5050612a38575060206123a1916129c1565b604051631bf137fb60e31b81526001600160a01b03851660048201526024810191909152604490fd5b1090508188612a26565b608051805160209091015160b05460405163488da99360e11b8152600481019390935260248301919091526044820152606490fd5b50608051612ab76020825192015160b05490613cb4565b10612357565b5050612306565b634e487b7160e01b600052601160045260246000fd5b90506020813d602011612b0e575b81612af5602093836139e2565b81010312610d9d575160ff81168103610d9d5783612191565b3d9150612ae8565b6040513d6000823e3d90fd5b612b2b90615bb5565b916121b8565b60405163ec998d1d60e01b815260c0516001600160a01b038481166004840152166024820152604490fd5b346107235760203660031901126107235760043560a25481101561072357610a496020916137fb565b34610723576020366003190112610723576001600160a01b03612ba6613774565b16610140515260a4602052602060ff6040610140512054166040519015158152f35b3461072357602036600319011261072357600435610140515260b16020526040610140512080546116036001830154926002810154906004600382015491015491604051958695869192608093969594919660a084019784526020840152604083015260608201520152565b3461072357612c42366137b6565b9091612c4c613a35565b612c55846147d3565b612c5e8561475b565b612c678461498b565b50604051906323b872dd60e01b602083015233602483015230604483015260648201526064815260a08101908082106001600160401b03831117610b2457604091909152612cbe906001600160a01b038516613a8b565b612cca61181884614834565b61014080516001600160a01b038616905260a460205251604081205491929160ff161590816130dc575b506130b357612d0284615bb5565b90612d1e612d108385613cb4565b60b454609a54918589614be8565b916402540be40092830383811161309957612d3a849186613cb4565b0490612d5e612d498387613ca7565b94612d56609d5487613cb4565b048095613ca7565b50612d698486613ca7565b9160018060a01b03609f54166040519063c778804760e01b825281604481016040600483015260a254809152606482019060a2600052600080516020615c8b8339815191529060005b818110613077575050509181806000946001602483015203915afa8015612b1657600090612fd0575b612de691508a614dd3565b6040516318160ddd60e01b81526020816004816001600160a01b038f165afa908115610715576101405191612f9e575b5080158015612f96575b15612f7a57505064e8d4a5100091612e3791613cb4565b04945b8510611c065760018060a01b038616610140515260a560205260406101405120612e65848254613a28565b905560018060a01b038716610140515260ab6020526040610140512060018060a01b038716600052602052612ea06040600020918254613a28565b9055612eaa614093565b6001600160a01b0386163b15610723576040516340c10f1960e01b815261014080516001600160a01b03938416600484015260248301879052905191929091839160449183918b165af1801561071557612f64575b50604080516001600160a01b039586168152602081019390935282019290925260608101919091523392909116907f43c967b388d3a4ccad3f7ab80167852e322e5a3fde9893f530252281b2ae8b709080608081015b0390a360016065556101405180f35b612f6d90613998565b610140518015612eff5780fd5b612f8b612f90946118db9394613cb4565b613cb4565b94612e3a565b508115612e20565b90506020813d602011612fc8575b81612fb9602093836139e2565b81010312610d9d57518b612e16565b3d9150612fac565b503d806000833e612fe181836139e2565b8101602082820312610d9d578151906001600160401b038211610d9d5780601f838501011215610d9d57818301519161301983614c69565b9361302760405195866139e2565b838552602085019260208560051b848401010111610d9d5790602081830101925b60208560051b83850101018410613067575050505050612de690612ddb565b8351815260209384019301613048565b82546001600160a01b0316845286945060209093019260019283019201612db2565b634e487b7160e01b61014051526011600452602461014051fd5b60405163039daf1d60e21b81526001600160a01b03868116600483015285166024820152604490fd5b6040915060a86020522060018060a01b0386166000526020526040600020541586612cf4565b346107235760403660031901126107235761311b613774565b61312361378a565b9060018060a01b03809116610140515260b56020526040610140512091166000526020526020604060002054604051908152f35b34610723576040366003190112610723576001600160a01b03613178613774565b16610140515260ac602052610140516040812090602435905260205260206040610140512054604051908152f35b34610723576040366003190112610723576131bf613774565b6131c761378a565b9060018060a01b03809116610140515260a86020526040610140512091166000526020526020604060002054604051908152f35b346107235761014051806003193601126107125760b2546040516001600160a01b039091168152602090f35b3461072357613235366137b6565b91613241949394613a35565b61324a85614720565b6132538461475b565b61325c8561498b565b50613266816147b8565b5061327085615b40565b9260018060a01b039384609f54166040519063c778804760e01b82528160448101916040600483015260a254809352606482019260a26101405152600080516020615c8b83398151915290610140515b818110613601575050506101405160248301528180610140519403915afa8015610715576101405190613570575b6132f9915087614dd3565b9480604051976318160ddd60e01b8952169660209283826004818c5afa9182156107155788878c926101405195613539575b506133566118db93613348876118db61335d99966118db96613cb4565b60b4549087609a5493614aef565b9a89613cb4565b946402540be400968703878111613099576133878861337f613394938a613cb4565b048098613ca7565b9761337f609d548a613cb4565b508510611c065787169081610140515260a58152604061014051206133ba878254613a28565b90556133c68686613a28565b87610140515260ab8252610140518360408220915282526040610140512090604051936133f28561397d565b825493848652613425600185015493828801948552600360028701549660408a0197885201549660608901978852613ca7565b80875283511161352057906003949392918b610140515260ab815261014051916040832092525260406101405120945185555160018501555160028401555191015561346f614093565b843b156107235760405163079cc67960e41b815261014051336004830152602482018490529094908580604481010381610140518a5af19485156107155784612f55936134e4927fd765e08eef31c0983ecca03ecd166297ac485ecd5dd69e291c848f0a020333c198613511575b50896148cb565b60405193849333988590949392606092608083019660018060a01b03168352602083015260408201520152565b61351a90613998565b8a6134dd565b60405163503e811160e11b815260048101839052602490fd5b94505050508382813d8311613569575b61355381836139e2565b810103126107235790519089888761335661332b565b503d613549565b3d8091833e61357f81836139e2565b8101906020908181840312610723578051906001600160401b03821161072357019180601f840112156107235782516135b781614c69565b936135c560405195866139e2565b818552838086019260051b820101928311610723578301905b8282106135f257505050506132f9906132ee565b815181529083019083016135de565b82548c168652602090950194869450600192830192016132c0565b3461072357610140518060031936011261071257602060b654604051908152f35b3461072357604036600319011261072357613656613774565b61365e61378a565b9060018060a01b03809116610140515260ab602052610140519060408220921690526020526080604061014051208054906001810154906003600282015491015491604051938452602084015260408301526060820152f35b3461072357610140518060031936011261071257609e546040516001600160a01b039091168152602090f35b34610723576020366003190112610723576001600160a01b03613704613774565b16610140515260b860205260206040610140512054604051908152f35b34610d9d576020366003190112610d9d57608061374d61373f613774565b613747613a03565b50614f7a565b60606040519180518352602081015160208401526040810151604084015201516060820152f35b600435906001600160a01b0382168203610d9d57565b602435906001600160a01b0382168203610d9d57565b604435906001600160a01b0382168203610d9d57565b60a0906003190112610d9d576001600160a01b036004358181168103610d9d57916024358281168103610d9d579160443591606435916084359081168103610d9d5790565b60a2548110156138205760a2600052600080516020615c8b8339815191520190600090565b634e487b7160e01b600052603260045260246000fd5b60aa548110156138205760aa6000527f550d3de95be0bd28a79c3eb4ea7f05692c60b0602e48b49461e703379b08a71a0190600090565b602435908115158203610d9d57565b6033546001600160a01b0316330361389057565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b603380546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b1561392457565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b608081019081106001600160401b03821117610b2457604052565b6001600160401b038111610b2457604052565b604081019081106001600160401b03821117610b2457604052565b61018081019081106001600160401b03821117610b2457604052565b90601f801991011681019081106001600160401b03821117610b2457604052565b60405190613a108261397d565b60006060838281528260208201528260408201520152565b91908201809211612ac457565b600260655414613a46576002606555565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60018060a01b031690604051613aa0816139ab565b6020928382527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564848301526000808486829651910182855af13d15613bc8573d916001600160401b038311613bb45790613b1a93929160405192613b0d88601f19601f84011601856139e2565b83523d868885013e613bd2565b805191821591848315613b8c575b505050905015613b355750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b919381809450010312613bb057820151908115158203610712575080388084613b28565b5080fd5b634e487b7160e01b85526041600452602485fd5b90613b1a92916060915b91929015613c345750815115613be6575090565b3b15613bef5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015613c475750805190602001fd5b60405162461bcd60e51b81526020600482015290819061080f9060248301905b919082519283825260005b848110613c93575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201613c72565b91908203918211612ac457565b81810292918115918404141715612ac457565b9060405160a081018181106001600160401b03821117610b2457604052608060048294805484526001810154602085015260028101546040850152600381015460608501520154910152565b8115613d1d570490565b634e487b7160e01b600052601260045260246000fd5b906002821015613d405752565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b03918216815291811660208301529091166040820152613d97929160a09190613d8a906060830190613d33565b8160808201520190613c67565b90565b81810392916000138015828513169184121617612ac457565b91909160008382019384129112908015821691151617612ac457565b91928315613e3f5784908215613e3757613de99284613f9a565b613df283613ea7565b916002811015613d4057613e2857613e0991613db3565b905b60008213613e1b57505050600090565b613d97926118db91613cb4565b613e3191613d9a565b90613e0b565b505050505090565b5050505050600090565b9190918215613e7b57838115613e7457613e0992613e6692613f4c565b613e6f83613ea7565b613d9a565b5050505090565b50505050600090565b919092938315613e3f5782859315613e3757613e0993613e6693613e6f92613f4c565b6001600160ff1b038111613eb85790565b60405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608490fd5b818102929160008212600160ff1b821416612ac4578184051490151715612ac457565b8115613d1d57600160ff1b8114600019831416612ac4570590565b9081158015613f92575b613f8a57613d9792613f85613f7f613f79613f736104e795613ea7565b95613ea7565b92613ea7565b84613d9a565b613f0e565b505050600090565b508015613f56565b909182158015613fee575b613e7b57613fb8613fb8613fbe92613ea7565b93613ea7565b906002811015613d4057613fdd57613d9792613f85836104e793613d9a565b613d9792613f856104e79284613d9a565b508015613fa5565b6001600160a01b039182168152918116602083015290911660408201526080810192916140269160600190613d33565b565b6020604051614036816139ab565b6000808252910181905280821291821561407c5761405390614082565b915b1561407357905b60405191614069836139ab565b8252602082015290565b5060019061405c565b91614055565b600160ff1b8114612ac45760000390565b609f546040805163c778804760e01b8082526004820183905260a2805460448401819052600091825260648401959094919392916001600160a01b03918216600080516020615c8b833981519152865b88811061435157505085858060019a8b60248301520381845afa9485156143475786956142b2575b508596939660aa54955b8987831061428f57505050600096879183519586928352806044840186600486015252606483019060a28552600080516020615c8b83398151915290855b8d828210614273575050505082809185602483015203915afa9283156142695786936141d0575b50509392919083945b868387106141a057505050506141999250613a28565b901c60b655565b90919293946141c490610ebf85856141b78b613836565b90549060031b1c16614dd3565b95019493929190614183565b909192503d8087833e6141e381836139e2565b81016020918281830312614265578051906001600160401b038211614261570181601f820112156142655780519061422661421d83614c69565b955195866139e2565b818552838086019260051b820101928311614261578301905b828210614252575050505090388061417a565b8151815290830190830161423f565b8880fd5b8780fd5b81513d88823e3d90fd5b83548a1685528d97508a96506020909401939283019201614153565b9091976142a790610ebf84886141b78d9e9b9e613836565b970190979497614115565b9094503d8087833e6142c481836139e2565b8101906020908181840312614265578051906001600160401b03821161426157019180601f840112156142655782516142fc81614c69565b93614309865195866139e2565b818552838086019260051b820101928311614343578301905b8282106143345750505050933861410b565b81518152908301908301614322565b8980fd5b82513d88823e3d90fd5b9098600160208192878d54168152019a0191016140e3565b60018060a01b038091169160009183835260a16020526040918284209182549260ff8416156143fb575050505082825260a360205260ff81832054166143e45782825260a36020528120805460ff191660011790557f6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d2629080a2565b516308ab912560e21b815260048101839052602490fd5b600160ff1980951617905560a360205283852060018482541617905560a254600160401b8110156144b257806001614436920160a2556137fb565b819291549060031b9188831b921b191617905584845260a460205260ff838520928354169115151617905560a25490600a8211614495575050807f6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d26291a2565b60449250519062d063d760e11b82526004820152600a6024820152fd5b634e487b7160e01b86526041600452602486fd5b9060018060a01b038092169260009084825260a160205260ff604083205416158015614566575b61454a5784825260a360205260ff604083205416158015614552575b61454a576002811015614536576145205750161490565b9116815260a4602052604090205460ff16919050565b634e487b7160e01b82526021600452602482fd5b509250505090565b50838316825260ff60408320541615614509565b50838316825260ff604083205416156144ed565b9060018060a01b038092169260009084825260a160205260ff6040832054161580156145525761454a576002811015614536576145205750161490565b919260018060a01b038093169360009185835260a160205260ff604084205416158015614633575b61462a57806145ff5761454a576002811015614536576145205750161490565b5084825260a360205260ff60408320541615806145095750838316825260ff60408320541615614509565b50509250505090565b50848416835260ff604084205416156145df565b929061466161466f92604051948593602085019788613ff6565b03601f1981018352826139e2565b51902090565b91939290938251151580614714575b614702578251946020840151958681106146d957506001600160a01b0316600090815260a560205260409020600301549394506146c193926159a4565b6146c757565b604051636108ecc160e01b8152600490fd5b60b05460405163488da99360e11b81526004810192909252602482018890526044820152606490fd5b604051631ee7bc0160e21b8152600490fd5b50602083015115614684565b6001600160a01b0316600081815260a1602052604090205460ff16156147435750565b602490604051906340d1d8df60e11b82526004820152fd5b6001600160a01b0316600081815260a7602052604090205460ff161561477e5750565b6024906040519063afd47d2360e01b82526004820152fd5b6001600160a01b0316156147a657565b60405163d92e233d60e01b8152600490fd5b80156147c15790565b604051631f2a200560e01b8152600490fd5b6001600160a01b0316600081815260a3602052604090205460ff16156147f65750565b6024906040519063d0957f1f60e01b82526004820152fd5b60a0546001600160a01b0316330361482257565b60405163cd44c14b60e01b8152600490fd5b6040516370a0823160e01b81523060048201526001600160a01b0391909116919060208082602481875afa918215612b165760009261489b575b5060a5908460005281815261488b60016040600020015484613ca7565b9460005252600160406000200155565b90918282813d83116148c4575b6148b281836139e2565b810103126107125750519060a561486e565b503d6148a8565b826148d557505050565b60405163a9059cbb60e01b6020808301919091526001600160a01b03938416602483015260448201949094529116919061491c906149168160648101614661565b83613a8b565b6040516370a0823160e01b8152306004820152918183602481845afa928315612b165760009361495b575b509060a59160005252600160406000200155565b90928282813d8311614984575b61497281836139e2565b810103126107125750519160a5614947565b503d614968565b60018060a01b03811690600082815260a56020526149b46149ae60408320613cc7565b92614f7a565b6040830190815180158015614ae6575b15614a5357505082604060609493614a21936149e660ae54612f8b8142613d13565b90525b86815260a560205220906080600491805184556020810151600185015560408101516002850155606081015160038501550151910155565b01907f5e804d42ae3b860f881d11cb44a4bb1f2f0d5b3d081f5539a32d6f97b629d97860208351604051908152a25190565b614a5d9042613ca7565b90614a6b60ae548093613d13565b908115614ad85793614a2193614ad1614aca889795604095614ab560609b988d885260ad602052614aad614aa28a8a205485613cb4565b602083015190613cb4565b905190613d13565b614ac38c8a01918251613a28565b9052613cb4565b8251613a28565b90526149e9565b505050505060609150015190565b508151156149c4565b919060af546000908015600014614bbe5750506000925b8315614bb557614b3884614b32614b2b614b3e95614b248496614f7a565b5190613cb4565b9586613ca7565b94614c4e565b92614c4e565b81811015614b8657506118db90614b559394613cb4565b60009181811115614b7f57614b6a9250613ca7565b6298968080821115614b7a575090565b905090565b5050614b6a565b614b9590613d97959392613a28565b60011c81811115614ba857505090613a28565b6118db90610ebf93613cb4565b50505050905090565b6118db6040614be29360018060a01b038816815260a6602052205460b65490613cb4565b92614b06565b919060af546000908015600014614c245750506000925b8315614bb557614b3884614b32614c1d614b3e95614b248496614f7a565b9586613a28565b6118db6040614c489360018060a01b038816815260a6602052205460b65490613cb4565b92614bff565b81811115614c605790613d9791613ca7565b613d9791613ca7565b6001600160401b038111610b245760051b60200190565b60018060a01b0380609f541691604051809363c778804760e01b825260448201926040600484015260a2548094526064830190600095869560a28752600080516020615c8b8339815191529187905b828210614d9e5750505050839182911515602483015203915afa918215614d91578192614cfb57505090565b9091503d8083833e614d0d81836139e2565b81016020918281830312614d89578051906001600160401b038211614d8d570181601f82011215614d8957805190614d4482614c69565b94614d5260405196876139e2565b828652848087019360051b83010193841161071257508301905b828210614d7a575050505090565b81518152908301908301614d6c565b8380fd5b8480fd5b50604051903d90823e3d90fd5b8354811686528998508a975060209095019460019384019390910190614ccf565b80518210156138205760209160051b010190565b600090819260a254905b818510614df157505050613d979150614f2b565b909192614dfd856137fb565b909160018060a01b03809354600393841b1c168060005260209060a1825260ff936040958587600020541615614f15578a908a16968760005260ab8552806000208460005285528060002093815195614e558761397d565b85548752600199614e868b88015496838a01978852600289015498868b01998a5201549560608a019687528d614dbf565b51998360005260a48352846000205416600014614ec2575050505050505061047f614eb693610442925190613cb4565b945b0193929190614ddd565b61044295614efd8b61047f97613e6f9b9c9a97614f0797614f0f9f97612f8b9760005260b58152826000209160005252600020549051613f4c565b9951905190613ca7565b905190613a28565b94614eb8565b634e487b7160e01b600052600160045260246000fd5b60008112614f365790565b606460405162461bcd60e51b815260206004820152602060248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152fd5b90614f83613a03565b60aa546060820193919291604080850191602080870160005b868110614faf5750505050505050909150565b614fb881613836565b919060018060a01b03809154600394851b1c168060005260ab908187528860002092881692836000528752614ff38d8a600020549051613a28565b8d5280600052818752886000208360005287528d61503e60019661501e888d60002001548a51613a28565b895283600052848a528b600020866000528a528b60002001548251613a28565b905260005285528660002090600052845261506160028760002001548851613a28565b875201614f9c565b91909493602061507885614f7a565b015160a0870151116154b65760e086015160018060a01b03851660005260a56020526150aa6040600020918254613a28565b90558260005260b16020526002604060002001549260005b60aa548110156154ac576150d581613836565b90546001600160a01b03600383901b82901c8116600081815260ac6020908152604080832089845282528083205493835260ab8252808320948d168352939052829020915190949390929091899086908e906151308761397d565b80548752600181015460208801526002810154604088015260030154606087015260a001519061515f91613cb4565b9061516991613d13565b600160a01b60019003828460031b1c1660005260ac60205260406000208760005260205260406000208181549061519f91613ca7565b90556020840151906151b091613ca7565b6020848101919091526101608d01516001600160a01b038a8116600081815260a885526040808220600389901b88901c90941682529285528281205491815260a99094529220549161520191613cb4565b9061520b91613d13565b83519061521791613a28565b61522090613ea7565b6101408d015161522f87613ea7565b61523891613f0e565b6152418b613ea7565b61524a91613f31565b61525391613d9a565b61525c90614f2b565b80845260208401511161548b576152936152846101208e015161527e88613ea7565b90613f0e565b61528d8b613ea7565b90613f31565b926002881015613d40578c8a6001978b878c156000146153845750506152c69260408501519060208151910151916154d7565b60408201525b858060a01b03828460031b1c1660005260ab6020526040600020868060a01b038c16600052602052600360606040600020928051845560208101518985015560408101516002850155015191015560008312928360001461537e5761533090614082565b925b604051938452156020840152848060a01b039160031b1c16907ffbd27ae8e0cbad564a4319af9e067e20be6a75a27dbbc7fb6ff8937c90378bea6040858060a01b038b1692a3016150c2565b92615332565b909261539d6040916118db61541f956020890151613cb4565b9401518a8060a01b03878960031b1c1660005260ab60205260406000208b8060a01b03851660005260205260036040600020015494808611600014615482576153e69086613ca7565b945b8b8060a01b03888a60031b1c1660005260b594856020526040600020908d8060a01b03166000526020528560406000205491613e84565b90888060a01b03858760031b1c166000526020526040600020888060a01b038c16600052602052604060002055868060a01b03838560031b1c1660005260ab6020526040600020878060a01b038b166000526020526003604060002001556152cc565b506000946153e8565b60405163503e811160e11b81526001600160a01b038b166004820152602490fd5b5050505050509050565b604051632333878560e01b81526001600160a01b0385166004820152602490fd5b926154f36154f994610ebf876118db856118db979a989a613cb4565b94613cb4565b6000918181111561550e57613d979250613ca7565b505090565b9061551d82614c69565b61552a60405191826139e2565b828152809261553b601f1991614c69565b0190602036910137565b60aa54929161555384615513565b9361555d81615513565b9561556782615513565b9560005b8381106156d157506001600160a01b03948516600081815260a4602052604081205491989160ff16156156c25750835b6000995b858b106155d35760848a8a8a8a604051936354cb2a9760e01b85526004850152166024830152604482015260016064820152fd5b6001809b019a8260005b8881106155ec5750505061559f565b6155f68185614dbf565b5180615605575b5082016155dd565b90919b6156168d6118db8484613cb4565b9088615637615625868b614dbf565b516156308784614dbf565b5190613ca7565b80841015615692575b509161566e9161565e82615658886156749897614dbf565b51613a28565b615668878d614dbf565b52613ca7565b9c613ca7565b908b1561568157386155fd565b505050505050955095505050505090565b8493508592989491509384916156a791613ca7565b978a6156b3848a614dbf565b60009052915091939293615640565b60409060a9602052205461559b565b6156da81613836565b919060018060a01b03809154600394851b1c168060005260209060ab825260409283600020818b1660005283528360002095606085519161571a8361397d565b88548352600198898101548785015260028101548885015201549101528a1660005260a4825260ff836000205416916000926000146157785750505050815b615763828c614dbf565b52600019615771828b614dbf565b520161556b565b60a88152838320918352522054615759565b60aa54929161579884615513565b936157a281615513565b956157ac82615513565b9560005b8381106158d757506001600160a01b03948516600081815260a4602052604081205491989160ff16156158c85750835b6000995b858b106158185760848a8a8a8a604051936354cb2a9760e01b85526004850152166024830152604482015260006064820152fd5b6001809b019a8260005b888110615831575050506157e4565b61583b8185614dbf565b518061584a575b508201615822565b90919b61585b8d6118db8484613cb4565b908861586a615625868b614dbf565b80841015615898575b509161566e9161565e826156588861588b9897614dbf565b908b156156815738615842565b8493508592989491509384916158ad91613ca7565b978a6158b9848a614dbf565b60009052915091939293615873565b60409060a960205220546157e0565b806158e461597c92613836565b9290888c60018060a01b03809354600397881b1c16806000528560209160ab83526040908d87836000209116600052845281600020968251966159268861397d565b8854885260019b8c8a015499878a019a8b526002810154868b0152015460608901521660005260a4845260ff8260002054169060009160001461598d5750505061597291508792614dbf565b5251905190613ca7565b615986828b614dbf565b52016157b0565b8460a8615972965283832091835252205492614dbf565b929190918351918215613e3f576159c26159d0926159dd9487615a38565b938551606087015191613f9a565b6104426020850151613ea7565b9060008212928315615a09575b5082156159f657505090565b615a0591925060985490613a28565b1190565b9092506402540be40090818302918383041483151715612ac4575160b354615a3091613cb4565b1191386159ea565b615a6c615a4d613d9794608084015190613ca7565b91615a616402540be4009384925190613cb4565b049260975490613cb4565b0490613a28565b6001600160a01b038116600081815260a4602052604081205490929060ff1615615b38575060206004916040519283809263313ce56760e01b82525afa8015615b2d578290615af1575b60ff915016601e0390601e8211615add57604d8211615add5750600a0a90565b634e487b7160e01b81526011600452602490fd5b506020813d8211615b25575b81615b0a602093836139e2565b81010312613bb0575160ff81168103613bb05760ff90615abd565b3d9150615afd565b6040513d84823e3d90fd5b9050613d9791505b609f546040516303b6b4bb60e51b81526001600160a01b039283166004820152600160248201529160209183916044918391165afa908115612b1657600091615b87575090565b906020823d8211615bad575b81615ba0602093836139e2565b8101031261071257505190565b3d9150615b93565b609f546040516303b6b4bb60e51b81526001600160a01b039283166004820152600060248201529160209183916044918391165afa908115612b1657600091615b87575090565b609f546040516303b6b4bb60e51b81526001600160a01b039283166004820152921515602484015260209183916044918391165afa908115612b1657600091615b87575090565b6001600160a01b038116600090815260ba6020526040902054908115615c8657615c6c90614f7a565b5111615c7457565b60405163eae579c360e01b8152600490fd5b505056feaaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42da2646970667358221220c6c0473432f3810fceba6188eccff56de44ec0344d15113732f4dd6d1477b54e64736f6c63430008130033
Deployed ByteCode
0x610160604052600436101561001357600080fd5b60006101405260003560e01c8063069d0254146137215780630a51f5f0146136e35780630d43e8ad146136b757806313a8b3e51461363d57806322c53fa51461361c5780632388dac1146132275780633545c789146131fb5780633e9ee375146131a6578063415f6820146131575780634b086657146131025780634b2fc7bb14612c34578063514ea4bf14612bc857806355a0c97114612b85578063578e5c2214612b5c5780635d8048db1461204557806360a2da4414611dd85780636c3e737914611db75780637127346414611d96578063715018a614611d315780637adbf97314611cc45780637dc0d1d014611c985780637e865aa4146117585780638da5cb5b1461172c5780639698d25a146116ee57806396c82e57146116cd5780639790576a1461168a578063a186159a1461164c578063a4f845dc14611607578063a912616914611589578063ab5770d314610f2e578063ae3302c214610f0d578063b45e670a14610ecf578063bab3e9e614610e55578063bc97c95e14610e17578063c0da840d14610da2578063c790281814610d4c578063c879c6d814610c8f578063c87fa42a14610c4c578063cb2d23ba14610c30578063ccfc2e8d14610bb4578063d0616ea814610a83578063d5eb058114610a62578063db38342314610a20578063ddc88817146109ff578063ddca3f43146109ab578063ef8250101461096d578063f2fde38b146108e0578063f6252c71146108ae578063f77c479114610882578063f794062e1461083f578063f9b6117f146108135763faf920121461025f57600080fd5b3461072357608036600319011261072357610278613774565b61028061378a565b6102886137a0565b9160026064351015610723576102a1606435848461457a565b156107e5576102af8361498b565b6102bd606435858585614647565b9182610140515260b16020526102f36102db60406101405120613cc7565b926102ea606435151587615bfc565b606435856159a4565b156107cc578151926104ec602084015160009060405196610313886139c6565b6000885260006020890152600060408901526000606089015260006080890152600060a0890152600060c0890152600060e089015260006101008901526000610120890152600061014089015260006101608901528651908082106000146107c45750905b8160208901526020870151918183109081156107b9575b50156107b257505b86526103a7606435151588615bfc565b60408701526103b588615a73565b60608701526103d86103d06040870151602089015190613cb4565b865190613d13565b60a08701526103f860208701516060870151604089015191606435613f9a565b610120870152610427602087015160018060a01b038a1660005260a56020526003604060002001549087615a38565b60c087015261045b6104486101208801516104428951613ea7565b90613db3565b61045560c0890151613ea7565b90613d9a565b61046b6098549161045583613ea7565b9161048461047f60208901518a5190613ca7565b613ea7565b6000841261079e575b6104a461049d60608b0151613ea7565b8095613f31565b6101008a015261012089015191600082121561079157506104c790600092613d9a565b91600060808a01525b60643561072a5750506104e7906104428851613ea7565b613f31565b61014085015261050560c0850151606086015190613d13565b6105226402540be40061051a609d5484613cb4565b048092613ca7565b61016086015260e085015261053c60643587878785615069565b807f8b372416ec9524b0238c4da0dc9f7d743dae07b6391152c6b768877d68c080b061016084896020898b8a5161057b848d0151608085015190613ca7565b60408d01519160408501519360c0610597610120880151614028565b960151604080516001600160a01b039b8c168152998b16898b015291909916908801529596956105cc60608901606435613d33565b608088015260a087015260c086015260e085015280516101008501520151610120830152610140820152a2610140515260b16020526106296040610140512060046000918281558260018201558260028201558260038201550155565b61063961010084015182876148cb565b61065461064d609854606086015190613d13565b33876148cb565b60b2546001600160a01b0316918261066e575b6101405180f35b806106a160c060206106af9451930151960151604051968793602085016040919493926060820195825260208201520152565b03601f1981018552846139e2565b813b15610723576106e094604051958694859384936388a494ff60e01b855261014051986064359260048701613d56565b039161014051905af18015610715576106fe575b8080808080610667565b61070790613998565b6101405180156106f4575b80fd5b6040513d61014051823e3d90fd5b6101405180fd5b818312610739575b5050613f31565b61074c60208901519160c08b0151613a28565b808211156107835761047f6107649161076993613ca7565b614082565b90508082131561077c57505b3880610732565b9050610775565b505061076961076482613ea7565b91929060808a01526104d0565b926107a99193613db3565b9160009261048d565b9050610397565b90508751143861038f565b905090610378565b60405163be12177560e01b815260048101849052602490fd5b5060405163ec998d1d60e01b81526001600160a01b03918216600482015291166024820152604490fd5b0390fd5b346107235761014051806003193601126107125760a0546040516001600160a01b039091168152602090f35b34610723576020366003190112610723576001600160a01b03610860613774565b16610140515260a3602052602060ff6040610140512054166040519015158152f35b346107235761014051806003193601126107125760b9546040516001600160a01b039091168152602090f35b34610723576040366003190112610723576106676108ca613774565b6108d261386d565b906108db61387c565b614369565b34610723576020366003190112610723576108f9613774565b61090161387c565b6001600160a01b0381161561091957610667906138d4565b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b34610723576020366003190112610723576001600160a01b0361098e613774565b16610140515260ad60205260206040610140512054604051908152f35b346107235761014051806003193601126107125760e0609754609854609954609a54609b5490609c5492609d5494604051968752602087015260408601526060850152608084015260a083015260c0820152f35b3461072357610140518060031936011261071257602060b454604051908152f35b346107235760203660031901126107235760043560aa5481101561072357610a49602091613836565b905460405160039290921b1c6001600160a01b03168152f35b3461072357610140518060031936011261071257602060b354604051908152f35b3461072357602036600319011261072357610a9c613774565b610aa461387c565b6001600160a01b039081168015610b775780610140515260a760205260ff604061014051205416610b3a5780610140515260a760205260406101405120600160ff1982541617905560aa54600160401b811015610b2457806001610b0b920160aa55613836565b909283549160031b92831b921b19161790556101405180f35b634e487b7160e01b600052604160045260246000fd5b60405162461bcd60e51b8152602060048201526015602482015274506f6f6c3a20616c7265616479207472616e63686560581b6044820152606490fd5b60405162461bcd60e51b8152602060048201526015602482015274506f6f6c3a20696e76616c6964206164647265737360581b6044820152606490fd5b3461072357602036600319011261072357610bcd613774565b610bd561387c565b610bde81614796565b60018060a01b0316609e5490806bffffffffffffffffffffffff60a01b831617609e5561014051809216177fc567a7e76455af13dfa1d15455b235923c14ccb050c95473d8341b6bafcc1a538280a280f35b3461072357610140518060031936011261071257610667614093565b34610723576020366003190112610723576001600160a01b03610c6d613774565b16610140515260a1602052602060ff6040610140512054166040519015158152f35b3461072357604036600319011261072357610ca8613774565b610cb061378a565b90610cba81614720565b609e546001600160a01b03919082163303610d3a577f6f8fef25a3cd63e7d1cae44c5eeaad06db500709a24fab9630fcc59d7b22642b9181169283610140515260a5602052610d1861014051928260408520918254958693556148cb565b604080516001600160a01b039290921682526020820192909252a26101405180f35b60405163a4cdd60360e01b8152600490fd5b3461072357608036600319011261072357610d65613774565b610d6d61378a565b90604435600281101561072357606435908115158203610d9d57602093610d93936145b7565b6040519015158152f35b600080fd5b3461072357602036600319011261072357610dbb613774565b610dc361387c565b610dcc81614796565b60a080546001600160a01b0319166001600160a01b0392909216918217905561014051907f3ca8ff425d27ae390700aab4fc3bd68ad54292e65f04097717a261f0c633acc88280a280f35b34610723576020366003190112610723576001600160a01b03610e38613774565b16610140515260a660205260206040610140512054604051908152f35b34610723576020366003190112610723576004358015158103610d9d57610e7d600091614c80565b60aa54600092915b818410610e9757602083604051908152f35b9091610ec5600191610ebf84610eac88613836565b868060a01b0391549060031b1c16614dd3565b90613a28565b9301929190610e85565b34610723576020366003190112610723576001600160a01b03610ef0613774565b16610140515260ba60205260206040610140512054604051908152f35b3461072357610140518060031936011261071257602060b054604051908152f35b346107235760e036600319011261072357610f47613774565b610f4f61378a565b610f576137a0565b91600260a43510156107235760c4356001600160a01b0381169003610d9d57610f7e61480e565b610f8b60a435848461457a565b156107e557610f998361498b565b90610fa860a435858584614647565b80610140515260b1602052610fc260406101405120613cc7565b8051156115655760405193610fd6856139c6565b6000855260006020860152600060408601526000606086015260006080860152600060a0860152600060c0860152600060e08601526000610100860152600061012086015260006101408601526000610160860152815160843580821060001461155e57505b80602087015260208301519060643590818310908115611553575b501561154c57505b855261106f60a435151587615bfc565b604086015261107d87615a73565b60608601526110a06110986040840151602088015190613cb4565b835190613d13565b60a08601526110c06020860151606084015160408801519160a435613f9a565b6101208601526110ef602086015160018060a01b03891660005260a56020526003604060002001549084615a38565b60c086015261111761110a6101208701516104428851613ea7565b61045560c0880151613ea7565b61112a61047f6020850151885190613ca7565b906000811261153c575b61114b6111446060890151613ea7565b8092613f31565b610100880152610120870151600083121561117257604051636108ecc160e01b8152600490fd5b61119492608089015260a435156000146114e1576104e7906104428951613ea7565b6101408601526111ad60c0860151606087015190613d13565b6111c26402540be40061051a609d5484613cb4565b61016087015260e08601526111e06020830151608087015190613ca7565b85526111f160a43588888887615069565b6112018251602087015190613ca7565b8252608082015261121b604082015160a086015190613ca7565b60408201526080840151602082015261123c604085015160a4358884614675565b817fcd04eb76238d1d18dc5b134bd1a2fc71184aedd9b40ee1970faef50d860d141261014085896020898b8151838301519060408401519260c0611284610120870151614028565b950151604080516001600160a01b039a8b168152988a16888a01529190981690870152606086015260808501529293926112c360a0860160a435613d33565b60c0850152805160e08501520151610100830152610120820152a280518061143557508051602080830151606080850151608080870151604097880151885197885295870194909452958501528301529181019190915281907f57646b4faf64a91c1ad76512fe716b11edf1056115e03bd65877e0640570ffb59060a090a2610140515260b16020526113746040610140512060046000918281558260018201558260028201558260038201550155565b61138661010083015160c435866148cb565b60b2546001600160a01b0316908161139f576101405180f35b6113d160208401516106a160c08651960151604051968793602085016040919493926060820195825260208201520152565b813b1561072357611402946040519586948593849363fd19608d60e01b8552610140519860a4359260048701613d56565b039161014051905af180156107155761141f575b80808080610667565b61142890613998565b6101405180156114165780fd5b6020828101516060808501516080808701516040808901518c8201518251998a52978901969096528701929092529185015283015260a08201526114dc929081907f569f4ef16f93b9d0b6625dcd44e8eb6e6ca8db330ee738654cd9fd57461499c79060c090a2610140515260b160205260406101405120906080600491805184556020810151600185015560408101516002850155606081015160038501550151910155565b611374565b6000811215613f3157602085015161150060c08a015160985490613a28565b8082111561152d5761047f6107649161151893613ca7565b808213156115265750613f31565b9050613f31565b50506115186107646000613ea7565b61154591613db3565b6000611134565b905061105f565b90508451148a611057565b905061103c565b505060405163c00d27c360e01b815293849361080f935060a4359260048601613ff6565b34610723576020366003190112610723576001600160a01b036115aa613774565b16610140515260a56020526040610140512080546116036001830154926002810154906004600382015491015491604051958695869192608093969594919660a084019784526020840152604083015260608201520152565b0390f35b34610723576040366003190112610723576020611644611625613774565b61163e61163061386d565b6116398361475b565b614c80565b90614dd3565b604051908152f35b34610723576020366003190112610723576001600160a01b0361166d613774565b16610140515260a960205260206040610140512054604051908152f35b34610723576020366003190112610723576001600160a01b036116ab613774565b16610140515260a7602052602060ff6040610140512054166040519015158152f35b3461072357610140518060031936011261071257602060af54604051908152f35b34610723576020366003190112610723576001600160a01b0361170f613774565b16610140515260b760205260206040610140512054604051908152f35b34610723576101405180600319360112610712576033546040516001600160a01b039091168152602090f35b346107235760a036600319011261072357611771613774565b61177961378a565b906064356001600160a01b0381169003610d9d576001600160401b038060843511610723573660236084350112156107235760843560040135116107235736602460843560040135608435010111610723576117d3613a35565b6117dc816147d3565b6117e582614720565b6001600160a01b0381811690831614611c76576118018161498b565b5061180b8261498b565b5061181d61181882614834565b6147b8565b9061182781615bb5565b9061183184615b40565b9161183c8185613cb4565b9260018060a01b038316610140515260a4602052610140519060ff6040832054169182611c56575b508115611c475761187e609b54609c54905b878688614be8565b9115611c3857611897609b54609c54905b87848b614aef565b61014051929080821115611c305750915b826402540be40003906402540be4008211611c1857506118e7926402540be4006118e08196946118db6118db958b613cb4565b613d13565b0496613cb4565b04926044358310611c06576402540be400611904609d5486613cb4565b04926119108486613ca7565b9360018060a01b038416610140515260a560205261193660406101405120918254613a28565b90556119428583613ca7565b61014080516001600160a01b038616905260a460205251604081205460ff169081611be6575b5015611bdc5761198687955b85611980858b8a61578a565b97615545565b92610140515b60aa54811015611a535780878a611a1d611a0c886118db611a05876119b260019a613836565b8b8060a01b0391549060031b1c16976119cb8282614dbf565b5189610140515260ab988960205260406101405120908d8060a01b03166000526020526119fe6040600020918254613ca7565b9055614dbf565b518a613cb4565b611a16858b614dbf565b5190613a28565b91610140515260205260406101405120838060a01b038916600052602052611a4b6040600020918254613a28565b90550161198c565b888287868b611a6183615c43565b611a6e82606435876148cb565b604080516001600160a01b03858116825287166020820152908101859052606081018390526080810182905233907fd6d34547c69c5ee3d2667625c188acf1006abb93e0ee7cf03925c67cf77604139060a090a260b2546001600160a01b03169182611ae1575b60016065556101405180f35b604051946020860152604085015260608401526080808401526084356004013560a08401526084356004013560246084350160c08501376101405160c06084356004013585010152611b4d60c084601f19601f60843560040135011681010360a08101865201846139e2565b803b1561072357604051638857560b60e01b81526001600160a01b0360648035821660048401529381166024830152949094166044850152608091840191909152610140519183919082908190611ba8906084830190613c67565b039161014051905af1801561071557611bc6575b8080808080611ad5565b611bcf90613998565b610140518015611bbc5780fd5b6119868495611974565b6001600160a01b03891690525061014051604090205460ff161588611968565b604051638199f5f360e01b8152600490fd5b634e487b7160e01b9052601160045261014051602490fd5b9050916118a8565b611897609954609a549061188f565b61187e609954609a5490611876565b6001600160a01b038816905261014051604090205460ff16915087611864565b6040516369ed396360e01b81526001600160a01b039091166004820152602490fd5b3461072357610140518060031936011261071257609f546040516001600160a01b039091168152602090f35b3461072357602036600319011261072357611cdd613774565b611ce561387c565b609f80546001600160a01b039283166001600160a01b0319821681179092556101405192167f05cd89403c6bdeac21c2ff33de395121a31fa1bc2bf3adf4825f1f86e79969dd8380a380f35b3461072357610140518060031936011261071257611d4d61387c565b603380546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36101405180f35b3461072357610140518060031936011261071257602060aa54604051908152f35b3461072357610140518060031936011261071257602060ae54604051908152f35b3461072357608036600319011261072357600435602435604435906064359061014051549260ff8460081c161593848095612038575b8015612021575b15611fc55760ff611e4891610140519087600184198316178355611fb4575b505460081c16611e438161391d565b61391d565b611e51336138d4565b610140515494611e6a60ff8760081c16611e438161391d565b60016065558015611fa2576020817f629b53ebf66271b592438aa954e367dad37de9cd1c1a2b9dc4acade7e1ff9f409260b055604051908152a16305f5e100808311611f8a57506c7e37be2022c0914b2680000000808211611f8a5750816040917f1c22ce892d949604d8532ddac8cca2e0199a1168487d121893beb4d2739700f9936097558060985582519182526020820152a1631dcd6500808211611f8a57506020817f361f687df539664645c65434f6ac8ca100a42a2411ee76fac9e2fbeeb07f33509260b355604051908152a16402540be400609d55611f4f576101405180f35b61ff00191661014051557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a180610667565b60249060405190630a253bc760e41b82526004820152fd5b604051633af35be560e11b8152600490fd5b61ffff191661010117815588611e34565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b158015611e155750600160ff821614611e15565b50600160ff821610611e0e565b346107235760a03660031901126107235761205e613774565b61206661378a565b9061206f6137a0565b60c052600260843510156107235761208561480e565b61209460843560c051846144c6565b15612b3157604051806101205261012081018181106001600160401b03821117610b24576040526101405190526101405160206101205101526101405160406101205101526101405160606101205101526101405160806101205101526101405160a06101205101526101405160c06101205101526101405160e06101205101526101405161010061012051015261213061181860c051614834565b602061012051015260c05160018060a01b03811660005260a460205260ff60406000205416600014612b22575060405163313ce56760e01b815260c051602090829060049082906001600160a01b03165afa908115612b1657600091612ada575b50601e60ff8216810311612ac457604d60ff8216601e0311612ac45760ff16601e03600a0a915b6121c9602061012051015184613cb4565b60406101205101526121dc60c05161498b565b6121ec60843560c0518486614647565b8060a052610140515260b160205261220960406101405120613cc7565b6080526122926000946122226084351560011485615bfc565b60a061012051015260643560c06101205101526122568161224885606435608051615a38565b806060610120510152613d13565b8060e06101205101526122746402540be40061051a609d5484613cb4565b610100610120510152608061012051015260c0610120510151613d13565b61012051526122c8608051516122af60c061012051015182613a28565b606060805101519060a061012051015192608435613dcf565b606060805101526122e760206080510151604061012051015190613a28565b6101205160600151610140519181811115612abd576123069250613ca7565b602060805101526123226080515160c061012051015190613a28565b60805152608080510152612340610120515160406080510151613a28565b6040608051015260c0610120510151151580612aa0575b612a6b5761237460a061012051015160843560c051608051614675565b61237f60c051614f7a565b80519060c061012051015161298c575b6020015161012051516123a191613a28565b1161296957608061012051015160018060a01b0360c05116610140515260a56020526123d560406101405120918254613a28565b905561014051610100526101205180511561294f575061012051516123fd8160c0518461578a565b610100525b610140515b610100515181101561272f5761241c81613836565b9190549161242d8261010051614dbf565b519260018060a01b03818360031b1c16610140515260ab6020526040610140512060018060a01b0360c05116600052602052600360406000206124756040518060e05261397d565b805460e051526001810154602060e05101526002810154604060e05101520154606060e05101526124fa6124b1866118db876101205151613cb4565b60018060a01b03838560031b1c16610140515260ac60205261014051604081209060a0519052602052604061014051206124ec828254613a28565b9055602060e0510151613a28565b602060e05101528761257161256861010061012051015160018060a01b038a16610140515260a86020526118db610140516040812060018060a01b03888a60031b1c166000526020526040600020549060018060a01b038d16905260a9602052604061014051205492613cb4565b60e05151613a28565b60e05152612715576001938560843561263857816125a5826125d59460e051516101205160e06020820151910151916154d7565b60e05152604060e05101516125c761012051606060c082015191015190613a28565b6040610120510151916154d7565b604060e05101525b838060a01b039160031b1c16610140515260ab60205260406101405120828060a01b0360c0511660005260205260406000206003606060e0518051845560208101518685015560408101516002850155015191015501612407565b6118db61264c9260c0610120510151613cb4565b60a061012051015190858060a01b03838560031b1c1660005260ab6020526040600020868060a01b0389166000526020526126cb6126936003604060002001549283613a28565b92878060a01b03858760031b1c1660005260b592836020526040600020898060a01b038c166000526020528460406000205491613e49565b600385811b85901c60a089901b899003908116600081815260209586526040808220938e168083529387528082209590955590815260ab85528381209181529352912001556125dd565b634e487b7160e01b61014051526021600452602461014051fd5b828460a051610140515260b160205261277a60805160406101405120906080600491805184556020810151600185015560408101516002850155606081015160038501550151910155565b6101006101205160208101519060c081015190606060a0820151910151916040519360018060a01b038716855260018060a01b0360c05116602086015260018060a01b0388166040860152606085015260808401526127de60a08401608435613d33565b60c083015260e08201527f8f1a004341b7c2e1e0799b80c6b849e04431c20757ba9b8c9064d5132405465d60a051928392a27f569f4ef16f93b9d0b6625dcd44e8eb6e6ca8db330ee738654cd9fd57461499c76080518051612888602083015192606081015190604060808201519101519060a061012051015192604051968796879260a094919796959260c0850198855260208501526040840152606083015260808201520152565b0390a260b2546001600160a01b0316806128a3576101405180f35b61012051906128ea60606040840151930151926128dc604051948592606435602085016040919493926060820195825260208201520152565b03601f1981018452836139e2565b803b156107235761291e936040518095819482936305c317db60e01b845261014051976084359160c0519160048701613d56565b039161014051905af1801561071557612939575b8080610667565b61294290613998565b6101405180156129325780fd5b602001516129608160c05184615545565b61010052612402565b60405163503e811160e11b815260c0516001600160a01b03166004820152602490fd5b600094506084356129e85761014080516001600160a01b038516905260b8602052516040902054806129c9575b5060206123a1915b91505061238f565b6402540be4006129df6020926123a19495613cb4565b049291506129b9565b61014080516001600160a01b038516905260b760205251604090205460608201516101205160c00151612a1a91613a28565b90818115159182612a61575b5050612a38575060206123a1916129c1565b604051631bf137fb60e31b81526001600160a01b03851660048201526024810191909152604490fd5b1090508188612a26565b608051805160209091015160b05460405163488da99360e11b8152600481019390935260248301919091526044820152606490fd5b50608051612ab76020825192015160b05490613cb4565b10612357565b5050612306565b634e487b7160e01b600052601160045260246000fd5b90506020813d602011612b0e575b81612af5602093836139e2565b81010312610d9d575160ff81168103610d9d5783612191565b3d9150612ae8565b6040513d6000823e3d90fd5b612b2b90615bb5565b916121b8565b60405163ec998d1d60e01b815260c0516001600160a01b038481166004840152166024820152604490fd5b346107235760203660031901126107235760043560a25481101561072357610a496020916137fb565b34610723576020366003190112610723576001600160a01b03612ba6613774565b16610140515260a4602052602060ff6040610140512054166040519015158152f35b3461072357602036600319011261072357600435610140515260b16020526040610140512080546116036001830154926002810154906004600382015491015491604051958695869192608093969594919660a084019784526020840152604083015260608201520152565b3461072357612c42366137b6565b9091612c4c613a35565b612c55846147d3565b612c5e8561475b565b612c678461498b565b50604051906323b872dd60e01b602083015233602483015230604483015260648201526064815260a08101908082106001600160401b03831117610b2457604091909152612cbe906001600160a01b038516613a8b565b612cca61181884614834565b61014080516001600160a01b038616905260a460205251604081205491929160ff161590816130dc575b506130b357612d0284615bb5565b90612d1e612d108385613cb4565b60b454609a54918589614be8565b916402540be40092830383811161309957612d3a849186613cb4565b0490612d5e612d498387613ca7565b94612d56609d5487613cb4565b048095613ca7565b50612d698486613ca7565b9160018060a01b03609f54166040519063c778804760e01b825281604481016040600483015260a254809152606482019060a2600052600080516020615c8b8339815191529060005b818110613077575050509181806000946001602483015203915afa8015612b1657600090612fd0575b612de691508a614dd3565b6040516318160ddd60e01b81526020816004816001600160a01b038f165afa908115610715576101405191612f9e575b5080158015612f96575b15612f7a57505064e8d4a5100091612e3791613cb4565b04945b8510611c065760018060a01b038616610140515260a560205260406101405120612e65848254613a28565b905560018060a01b038716610140515260ab6020526040610140512060018060a01b038716600052602052612ea06040600020918254613a28565b9055612eaa614093565b6001600160a01b0386163b15610723576040516340c10f1960e01b815261014080516001600160a01b03938416600484015260248301879052905191929091839160449183918b165af1801561071557612f64575b50604080516001600160a01b039586168152602081019390935282019290925260608101919091523392909116907f43c967b388d3a4ccad3f7ab80167852e322e5a3fde9893f530252281b2ae8b709080608081015b0390a360016065556101405180f35b612f6d90613998565b610140518015612eff5780fd5b612f8b612f90946118db9394613cb4565b613cb4565b94612e3a565b508115612e20565b90506020813d602011612fc8575b81612fb9602093836139e2565b81010312610d9d57518b612e16565b3d9150612fac565b503d806000833e612fe181836139e2565b8101602082820312610d9d578151906001600160401b038211610d9d5780601f838501011215610d9d57818301519161301983614c69565b9361302760405195866139e2565b838552602085019260208560051b848401010111610d9d5790602081830101925b60208560051b83850101018410613067575050505050612de690612ddb565b8351815260209384019301613048565b82546001600160a01b0316845286945060209093019260019283019201612db2565b634e487b7160e01b61014051526011600452602461014051fd5b60405163039daf1d60e21b81526001600160a01b03868116600483015285166024820152604490fd5b6040915060a86020522060018060a01b0386166000526020526040600020541586612cf4565b346107235760403660031901126107235761311b613774565b61312361378a565b9060018060a01b03809116610140515260b56020526040610140512091166000526020526020604060002054604051908152f35b34610723576040366003190112610723576001600160a01b03613178613774565b16610140515260ac602052610140516040812090602435905260205260206040610140512054604051908152f35b34610723576040366003190112610723576131bf613774565b6131c761378a565b9060018060a01b03809116610140515260a86020526040610140512091166000526020526020604060002054604051908152f35b346107235761014051806003193601126107125760b2546040516001600160a01b039091168152602090f35b3461072357613235366137b6565b91613241949394613a35565b61324a85614720565b6132538461475b565b61325c8561498b565b50613266816147b8565b5061327085615b40565b9260018060a01b039384609f54166040519063c778804760e01b82528160448101916040600483015260a254809352606482019260a26101405152600080516020615c8b83398151915290610140515b818110613601575050506101405160248301528180610140519403915afa8015610715576101405190613570575b6132f9915087614dd3565b9480604051976318160ddd60e01b8952169660209283826004818c5afa9182156107155788878c926101405195613539575b506133566118db93613348876118db61335d99966118db96613cb4565b60b4549087609a5493614aef565b9a89613cb4565b946402540be400968703878111613099576133878861337f613394938a613cb4565b048098613ca7565b9761337f609d548a613cb4565b508510611c065787169081610140515260a58152604061014051206133ba878254613a28565b90556133c68686613a28565b87610140515260ab8252610140518360408220915282526040610140512090604051936133f28561397d565b825493848652613425600185015493828801948552600360028701549660408a0197885201549660608901978852613ca7565b80875283511161352057906003949392918b610140515260ab815261014051916040832092525260406101405120945185555160018501555160028401555191015561346f614093565b843b156107235760405163079cc67960e41b815261014051336004830152602482018490529094908580604481010381610140518a5af19485156107155784612f55936134e4927fd765e08eef31c0983ecca03ecd166297ac485ecd5dd69e291c848f0a020333c198613511575b50896148cb565b60405193849333988590949392606092608083019660018060a01b03168352602083015260408201520152565b61351a90613998565b8a6134dd565b60405163503e811160e11b815260048101839052602490fd5b94505050508382813d8311613569575b61355381836139e2565b810103126107235790519089888761335661332b565b503d613549565b3d8091833e61357f81836139e2565b8101906020908181840312610723578051906001600160401b03821161072357019180601f840112156107235782516135b781614c69565b936135c560405195866139e2565b818552838086019260051b820101928311610723578301905b8282106135f257505050506132f9906132ee565b815181529083019083016135de565b82548c168652602090950194869450600192830192016132c0565b3461072357610140518060031936011261071257602060b654604051908152f35b3461072357604036600319011261072357613656613774565b61365e61378a565b9060018060a01b03809116610140515260ab602052610140519060408220921690526020526080604061014051208054906001810154906003600282015491015491604051938452602084015260408301526060820152f35b3461072357610140518060031936011261071257609e546040516001600160a01b039091168152602090f35b34610723576020366003190112610723576001600160a01b03613704613774565b16610140515260b860205260206040610140512054604051908152f35b34610d9d576020366003190112610d9d57608061374d61373f613774565b613747613a03565b50614f7a565b60606040519180518352602081015160208401526040810151604084015201516060820152f35b600435906001600160a01b0382168203610d9d57565b602435906001600160a01b0382168203610d9d57565b604435906001600160a01b0382168203610d9d57565b60a0906003190112610d9d576001600160a01b036004358181168103610d9d57916024358281168103610d9d579160443591606435916084359081168103610d9d5790565b60a2548110156138205760a2600052600080516020615c8b8339815191520190600090565b634e487b7160e01b600052603260045260246000fd5b60aa548110156138205760aa6000527f550d3de95be0bd28a79c3eb4ea7f05692c60b0602e48b49461e703379b08a71a0190600090565b602435908115158203610d9d57565b6033546001600160a01b0316330361389057565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b603380546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b1561392457565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b608081019081106001600160401b03821117610b2457604052565b6001600160401b038111610b2457604052565b604081019081106001600160401b03821117610b2457604052565b61018081019081106001600160401b03821117610b2457604052565b90601f801991011681019081106001600160401b03821117610b2457604052565b60405190613a108261397d565b60006060838281528260208201528260408201520152565b91908201809211612ac457565b600260655414613a46576002606555565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b60018060a01b031690604051613aa0816139ab565b6020928382527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564848301526000808486829651910182855af13d15613bc8573d916001600160401b038311613bb45790613b1a93929160405192613b0d88601f19601f84011601856139e2565b83523d868885013e613bd2565b805191821591848315613b8c575b505050905015613b355750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b919381809450010312613bb057820151908115158203610712575080388084613b28565b5080fd5b634e487b7160e01b85526041600452602485fd5b90613b1a92916060915b91929015613c345750815115613be6575090565b3b15613bef5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015613c475750805190602001fd5b60405162461bcd60e51b81526020600482015290819061080f9060248301905b919082519283825260005b848110613c93575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201613c72565b91908203918211612ac457565b81810292918115918404141715612ac457565b9060405160a081018181106001600160401b03821117610b2457604052608060048294805484526001810154602085015260028101546040850152600381015460608501520154910152565b8115613d1d570490565b634e487b7160e01b600052601260045260246000fd5b906002821015613d405752565b634e487b7160e01b600052602160045260246000fd5b6001600160a01b03918216815291811660208301529091166040820152613d97929160a09190613d8a906060830190613d33565b8160808201520190613c67565b90565b81810392916000138015828513169184121617612ac457565b91909160008382019384129112908015821691151617612ac457565b91928315613e3f5784908215613e3757613de99284613f9a565b613df283613ea7565b916002811015613d4057613e2857613e0991613db3565b905b60008213613e1b57505050600090565b613d97926118db91613cb4565b613e3191613d9a565b90613e0b565b505050505090565b5050505050600090565b9190918215613e7b57838115613e7457613e0992613e6692613f4c565b613e6f83613ea7565b613d9a565b5050505090565b50505050600090565b919092938315613e3f5782859315613e3757613e0993613e6693613e6f92613f4c565b6001600160ff1b038111613eb85790565b60405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b6064820152608490fd5b818102929160008212600160ff1b821416612ac4578184051490151715612ac457565b8115613d1d57600160ff1b8114600019831416612ac4570590565b9081158015613f92575b613f8a57613d9792613f85613f7f613f79613f736104e795613ea7565b95613ea7565b92613ea7565b84613d9a565b613f0e565b505050600090565b508015613f56565b909182158015613fee575b613e7b57613fb8613fb8613fbe92613ea7565b93613ea7565b906002811015613d4057613fdd57613d9792613f85836104e793613d9a565b613d9792613f856104e79284613d9a565b508015613fa5565b6001600160a01b039182168152918116602083015290911660408201526080810192916140269160600190613d33565b565b6020604051614036816139ab565b6000808252910181905280821291821561407c5761405390614082565b915b1561407357905b60405191614069836139ab565b8252602082015290565b5060019061405c565b91614055565b600160ff1b8114612ac45760000390565b609f546040805163c778804760e01b8082526004820183905260a2805460448401819052600091825260648401959094919392916001600160a01b03918216600080516020615c8b833981519152865b88811061435157505085858060019a8b60248301520381845afa9485156143475786956142b2575b508596939660aa54955b8987831061428f57505050600096879183519586928352806044840186600486015252606483019060a28552600080516020615c8b83398151915290855b8d828210614273575050505082809185602483015203915afa9283156142695786936141d0575b50509392919083945b868387106141a057505050506141999250613a28565b901c60b655565b90919293946141c490610ebf85856141b78b613836565b90549060031b1c16614dd3565b95019493929190614183565b909192503d8087833e6141e381836139e2565b81016020918281830312614265578051906001600160401b038211614261570181601f820112156142655780519061422661421d83614c69565b955195866139e2565b818552838086019260051b820101928311614261578301905b828210614252575050505090388061417a565b8151815290830190830161423f565b8880fd5b8780fd5b81513d88823e3d90fd5b83548a1685528d97508a96506020909401939283019201614153565b9091976142a790610ebf84886141b78d9e9b9e613836565b970190979497614115565b9094503d8087833e6142c481836139e2565b8101906020908181840312614265578051906001600160401b03821161426157019180601f840112156142655782516142fc81614c69565b93614309865195866139e2565b818552838086019260051b820101928311614343578301905b8282106143345750505050933861410b565b81518152908301908301614322565b8980fd5b82513d88823e3d90fd5b9098600160208192878d54168152019a0191016140e3565b60018060a01b038091169160009183835260a16020526040918284209182549260ff8416156143fb575050505082825260a360205260ff81832054166143e45782825260a36020528120805460ff191660011790557f6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d2629080a2565b516308ab912560e21b815260048101839052602490fd5b600160ff1980951617905560a360205283852060018482541617905560a254600160401b8110156144b257806001614436920160a2556137fb565b819291549060031b9188831b921b191617905584845260a460205260ff838520928354169115151617905560a25490600a8211614495575050807f6a65f90b1a644d2faac467a21e07e50e3f8fa5846e26231d30ae79a417d3d26291a2565b60449250519062d063d760e11b82526004820152600a6024820152fd5b634e487b7160e01b86526041600452602486fd5b9060018060a01b038092169260009084825260a160205260ff604083205416158015614566575b61454a5784825260a360205260ff604083205416158015614552575b61454a576002811015614536576145205750161490565b9116815260a4602052604090205460ff16919050565b634e487b7160e01b82526021600452602482fd5b509250505090565b50838316825260ff60408320541615614509565b50838316825260ff604083205416156144ed565b9060018060a01b038092169260009084825260a160205260ff6040832054161580156145525761454a576002811015614536576145205750161490565b919260018060a01b038093169360009185835260a160205260ff604084205416158015614633575b61462a57806145ff5761454a576002811015614536576145205750161490565b5084825260a360205260ff60408320541615806145095750838316825260ff60408320541615614509565b50509250505090565b50848416835260ff604084205416156145df565b929061466161466f92604051948593602085019788613ff6565b03601f1981018352826139e2565b51902090565b91939290938251151580614714575b614702578251946020840151958681106146d957506001600160a01b0316600090815260a560205260409020600301549394506146c193926159a4565b6146c757565b604051636108ecc160e01b8152600490fd5b60b05460405163488da99360e11b81526004810192909252602482018890526044820152606490fd5b604051631ee7bc0160e21b8152600490fd5b50602083015115614684565b6001600160a01b0316600081815260a1602052604090205460ff16156147435750565b602490604051906340d1d8df60e11b82526004820152fd5b6001600160a01b0316600081815260a7602052604090205460ff161561477e5750565b6024906040519063afd47d2360e01b82526004820152fd5b6001600160a01b0316156147a657565b60405163d92e233d60e01b8152600490fd5b80156147c15790565b604051631f2a200560e01b8152600490fd5b6001600160a01b0316600081815260a3602052604090205460ff16156147f65750565b6024906040519063d0957f1f60e01b82526004820152fd5b60a0546001600160a01b0316330361482257565b60405163cd44c14b60e01b8152600490fd5b6040516370a0823160e01b81523060048201526001600160a01b0391909116919060208082602481875afa918215612b165760009261489b575b5060a5908460005281815261488b60016040600020015484613ca7565b9460005252600160406000200155565b90918282813d83116148c4575b6148b281836139e2565b810103126107125750519060a561486e565b503d6148a8565b826148d557505050565b60405163a9059cbb60e01b6020808301919091526001600160a01b03938416602483015260448201949094529116919061491c906149168160648101614661565b83613a8b565b6040516370a0823160e01b8152306004820152918183602481845afa928315612b165760009361495b575b509060a59160005252600160406000200155565b90928282813d8311614984575b61497281836139e2565b810103126107125750519160a5614947565b503d614968565b60018060a01b03811690600082815260a56020526149b46149ae60408320613cc7565b92614f7a565b6040830190815180158015614ae6575b15614a5357505082604060609493614a21936149e660ae54612f8b8142613d13565b90525b86815260a560205220906080600491805184556020810151600185015560408101516002850155606081015160038501550151910155565b01907f5e804d42ae3b860f881d11cb44a4bb1f2f0d5b3d081f5539a32d6f97b629d97860208351604051908152a25190565b614a5d9042613ca7565b90614a6b60ae548093613d13565b908115614ad85793614a2193614ad1614aca889795604095614ab560609b988d885260ad602052614aad614aa28a8a205485613cb4565b602083015190613cb4565b905190613d13565b614ac38c8a01918251613a28565b9052613cb4565b8251613a28565b90526149e9565b505050505060609150015190565b508151156149c4565b919060af546000908015600014614bbe5750506000925b8315614bb557614b3884614b32614b2b614b3e95614b248496614f7a565b5190613cb4565b9586613ca7565b94614c4e565b92614c4e565b81811015614b8657506118db90614b559394613cb4565b60009181811115614b7f57614b6a9250613ca7565b6298968080821115614b7a575090565b905090565b5050614b6a565b614b9590613d97959392613a28565b60011c81811115614ba857505090613a28565b6118db90610ebf93613cb4565b50505050905090565b6118db6040614be29360018060a01b038816815260a6602052205460b65490613cb4565b92614b06565b919060af546000908015600014614c245750506000925b8315614bb557614b3884614b32614c1d614b3e95614b248496614f7a565b9586613a28565b6118db6040614c489360018060a01b038816815260a6602052205460b65490613cb4565b92614bff565b81811115614c605790613d9791613ca7565b613d9791613ca7565b6001600160401b038111610b245760051b60200190565b60018060a01b0380609f541691604051809363c778804760e01b825260448201926040600484015260a2548094526064830190600095869560a28752600080516020615c8b8339815191529187905b828210614d9e5750505050839182911515602483015203915afa918215614d91578192614cfb57505090565b9091503d8083833e614d0d81836139e2565b81016020918281830312614d89578051906001600160401b038211614d8d570181601f82011215614d8957805190614d4482614c69565b94614d5260405196876139e2565b828652848087019360051b83010193841161071257508301905b828210614d7a575050505090565b81518152908301908301614d6c565b8380fd5b8480fd5b50604051903d90823e3d90fd5b8354811686528998508a975060209095019460019384019390910190614ccf565b80518210156138205760209160051b010190565b600090819260a254905b818510614df157505050613d979150614f2b565b909192614dfd856137fb565b909160018060a01b03809354600393841b1c168060005260209060a1825260ff936040958587600020541615614f15578a908a16968760005260ab8552806000208460005285528060002093815195614e558761397d565b85548752600199614e868b88015496838a01978852600289015498868b01998a5201549560608a019687528d614dbf565b51998360005260a48352846000205416600014614ec2575050505050505061047f614eb693610442925190613cb4565b945b0193929190614ddd565b61044295614efd8b61047f97613e6f9b9c9a97614f0797614f0f9f97612f8b9760005260b58152826000209160005252600020549051613f4c565b9951905190613ca7565b905190613a28565b94614eb8565b634e487b7160e01b600052600160045260246000fd5b60008112614f365790565b606460405162461bcd60e51b815260206004820152602060248201527f53616665436173743a2076616c7565206d75737420626520706f7369746976656044820152fd5b90614f83613a03565b60aa546060820193919291604080850191602080870160005b868110614faf5750505050505050909150565b614fb881613836565b919060018060a01b03809154600394851b1c168060005260ab908187528860002092881692836000528752614ff38d8a600020549051613a28565b8d5280600052818752886000208360005287528d61503e60019661501e888d60002001548a51613a28565b895283600052848a528b600020866000528a528b60002001548251613a28565b905260005285528660002090600052845261506160028760002001548851613a28565b875201614f9c565b91909493602061507885614f7a565b015160a0870151116154b65760e086015160018060a01b03851660005260a56020526150aa6040600020918254613a28565b90558260005260b16020526002604060002001549260005b60aa548110156154ac576150d581613836565b90546001600160a01b03600383901b82901c8116600081815260ac6020908152604080832089845282528083205493835260ab8252808320948d168352939052829020915190949390929091899086908e906151308761397d565b80548752600181015460208801526002810154604088015260030154606087015260a001519061515f91613cb4565b9061516991613d13565b600160a01b60019003828460031b1c1660005260ac60205260406000208760005260205260406000208181549061519f91613ca7565b90556020840151906151b091613ca7565b6020848101919091526101608d01516001600160a01b038a8116600081815260a885526040808220600389901b88901c90941682529285528281205491815260a99094529220549161520191613cb4565b9061520b91613d13565b83519061521791613a28565b61522090613ea7565b6101408d015161522f87613ea7565b61523891613f0e565b6152418b613ea7565b61524a91613f31565b61525391613d9a565b61525c90614f2b565b80845260208401511161548b576152936152846101208e015161527e88613ea7565b90613f0e565b61528d8b613ea7565b90613f31565b926002881015613d40578c8a6001978b878c156000146153845750506152c69260408501519060208151910151916154d7565b60408201525b858060a01b03828460031b1c1660005260ab6020526040600020868060a01b038c16600052602052600360606040600020928051845560208101518985015560408101516002850155015191015560008312928360001461537e5761533090614082565b925b604051938452156020840152848060a01b039160031b1c16907ffbd27ae8e0cbad564a4319af9e067e20be6a75a27dbbc7fb6ff8937c90378bea6040858060a01b038b1692a3016150c2565b92615332565b909261539d6040916118db61541f956020890151613cb4565b9401518a8060a01b03878960031b1c1660005260ab60205260406000208b8060a01b03851660005260205260036040600020015494808611600014615482576153e69086613ca7565b945b8b8060a01b03888a60031b1c1660005260b594856020526040600020908d8060a01b03166000526020528560406000205491613e84565b90888060a01b03858760031b1c166000526020526040600020888060a01b038c16600052602052604060002055868060a01b03838560031b1c1660005260ab6020526040600020878060a01b038b166000526020526003604060002001556152cc565b506000946153e8565b60405163503e811160e11b81526001600160a01b038b166004820152602490fd5b5050505050509050565b604051632333878560e01b81526001600160a01b0385166004820152602490fd5b926154f36154f994610ebf876118db856118db979a989a613cb4565b94613cb4565b6000918181111561550e57613d979250613ca7565b505090565b9061551d82614c69565b61552a60405191826139e2565b828152809261553b601f1991614c69565b0190602036910137565b60aa54929161555384615513565b9361555d81615513565b9561556782615513565b9560005b8381106156d157506001600160a01b03948516600081815260a4602052604081205491989160ff16156156c25750835b6000995b858b106155d35760848a8a8a8a604051936354cb2a9760e01b85526004850152166024830152604482015260016064820152fd5b6001809b019a8260005b8881106155ec5750505061559f565b6155f68185614dbf565b5180615605575b5082016155dd565b90919b6156168d6118db8484613cb4565b9088615637615625868b614dbf565b516156308784614dbf565b5190613ca7565b80841015615692575b509161566e9161565e82615658886156749897614dbf565b51613a28565b615668878d614dbf565b52613ca7565b9c613ca7565b908b1561568157386155fd565b505050505050955095505050505090565b8493508592989491509384916156a791613ca7565b978a6156b3848a614dbf565b60009052915091939293615640565b60409060a9602052205461559b565b6156da81613836565b919060018060a01b03809154600394851b1c168060005260209060ab825260409283600020818b1660005283528360002095606085519161571a8361397d565b88548352600198898101548785015260028101548885015201549101528a1660005260a4825260ff836000205416916000926000146157785750505050815b615763828c614dbf565b52600019615771828b614dbf565b520161556b565b60a88152838320918352522054615759565b60aa54929161579884615513565b936157a281615513565b956157ac82615513565b9560005b8381106158d757506001600160a01b03948516600081815260a4602052604081205491989160ff16156158c85750835b6000995b858b106158185760848a8a8a8a604051936354cb2a9760e01b85526004850152166024830152604482015260006064820152fd5b6001809b019a8260005b888110615831575050506157e4565b61583b8185614dbf565b518061584a575b508201615822565b90919b61585b8d6118db8484613cb4565b908861586a615625868b614dbf565b80841015615898575b509161566e9161565e826156588861588b9897614dbf565b908b156156815738615842565b8493508592989491509384916158ad91613ca7565b978a6158b9848a614dbf565b60009052915091939293615873565b60409060a960205220546157e0565b806158e461597c92613836565b9290888c60018060a01b03809354600397881b1c16806000528560209160ab83526040908d87836000209116600052845281600020968251966159268861397d565b8854885260019b8c8a015499878a019a8b526002810154868b0152015460608901521660005260a4845260ff8260002054169060009160001461598d5750505061597291508792614dbf565b5251905190613ca7565b615986828b614dbf565b52016157b0565b8460a8615972965283832091835252205492614dbf565b929190918351918215613e3f576159c26159d0926159dd9487615a38565b938551606087015191613f9a565b6104426020850151613ea7565b9060008212928315615a09575b5082156159f657505090565b615a0591925060985490613a28565b1190565b9092506402540be40090818302918383041483151715612ac4575160b354615a3091613cb4565b1191386159ea565b615a6c615a4d613d9794608084015190613ca7565b91615a616402540be4009384925190613cb4565b049260975490613cb4565b0490613a28565b6001600160a01b038116600081815260a4602052604081205490929060ff1615615b38575060206004916040519283809263313ce56760e01b82525afa8015615b2d578290615af1575b60ff915016601e0390601e8211615add57604d8211615add5750600a0a90565b634e487b7160e01b81526011600452602490fd5b506020813d8211615b25575b81615b0a602093836139e2565b81010312613bb0575160ff81168103613bb05760ff90615abd565b3d9150615afd565b6040513d84823e3d90fd5b9050613d9791505b609f546040516303b6b4bb60e51b81526001600160a01b039283166004820152600160248201529160209183916044918391165afa908115612b1657600091615b87575090565b906020823d8211615bad575b81615ba0602093836139e2565b8101031261071257505190565b3d9150615b93565b609f546040516303b6b4bb60e51b81526001600160a01b039283166004820152600060248201529160209183916044918391165afa908115612b1657600091615b87575090565b609f546040516303b6b4bb60e51b81526001600160a01b039283166004820152921515602484015260209183916044918391165afa908115612b1657600091615b87575090565b6001600160a01b038116600090815260ba6020526040902054908115615c8657615c6c90614f7a565b5111615c7457565b60405163eae579c360e01b8152600490fd5b505056feaaf4f58de99300cfadc4585755f376d5fa747d5bc561d5bd9d710de1f91bf42da2646970667358221220c6c0473432f3810fceba6188eccff56de44ec0344d15113732f4dd6d1477b54e64736f6c63430008130033