More Info
Private Name Tags
ContractCreator
Sponsored
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336701 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH | ||||
107336694 | 414 days ago | 0 ETH |
Loading...
Loading
Contract Name:
AccountBalance
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; pragma abicoder v2; import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; import { SafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; import { SignedSafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol"; import { FullMath } from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; import { BlockContext } from "./base/BlockContext.sol"; import { ClearingHouseCallee } from "./base/ClearingHouseCallee.sol"; import { IAccountBalance } from "./interface/IAccountBalance.sol"; import { IBaseToken } from "./interface/IBaseToken.sol"; import { IClearingHouseConfig } from "./interface/IClearingHouseConfig.sol"; import { IExchange } from "./interface/IExchange.sol"; import { IIndexPrice } from "./interface/IIndexPrice.sol"; import { IOrderBook } from "./interface/IOrderBook.sol"; import { PerpSafeCast } from "./lib/PerpSafeCast.sol"; import { PerpMath } from "./lib/PerpMath.sol"; import { AccountBalanceStorageV1, AccountMarket } from "./storage/AccountBalanceStorage.sol"; // never inherit any new stateful contract. never change the orders of parent stateful contracts contract AccountBalance is IAccountBalance, BlockContext, ClearingHouseCallee, AccountBalanceStorageV1 { using AddressUpgradeable for address; using SafeMathUpgradeable for uint256; using SignedSafeMathUpgradeable for int256; using PerpSafeCast for uint256; using PerpSafeCast for int256; using PerpMath for uint256; using PerpMath for int256; using PerpMath for uint160; using AccountMarket for AccountMarket.Info; // // CONSTANT // uint256 internal constant _DUST = 10 wei; uint256 internal constant _MIN_PARTIAL_LIQUIDATE_POSITION_VALUE = 100e18 wei; // 100 USD in decimal 18 // // EXTERNAL NON-VIEW // function initialize(address clearingHouseConfigArg, address orderBookArg) external initializer { // IClearingHouseConfig address is not contract require(clearingHouseConfigArg.isContract(), "AB_CHCNC"); // IOrderBook is not contract require(orderBookArg.isContract(), "AB_OBNC"); __ClearingHouseCallee_init(); _clearingHouseConfig = clearingHouseConfigArg; _orderBook = orderBookArg; } function setVault(address vaultArg) external onlyOwner { // vault address is not contract require(vaultArg.isContract(), "AB_VNC"); _vault = vaultArg; emit VaultChanged(vaultArg); } /// @inheritdoc IAccountBalance function modifyTakerBalance( address trader, address baseToken, int256 base, int256 quote ) external override returns (int256, int256) { _requireOnlyClearingHouse(); return _modifyTakerBalance(trader, baseToken, base, quote); } /// @inheritdoc IAccountBalance function modifyOwedRealizedPnl(address trader, int256 amount) external override { _requireOnlyClearingHouse(); _modifyOwedRealizedPnl(trader, amount); } /// @inheritdoc IAccountBalance function settleQuoteToOwedRealizedPnl( address trader, address baseToken, int256 amount ) external override { _requireOnlyClearingHouse(); _settleQuoteToOwedRealizedPnl(trader, baseToken, amount); } /// @inheritdoc IAccountBalance function settleOwedRealizedPnl(address trader) external override returns (int256) { // only vault require(_msgSender() == _vault, "AB_OV"); int256 owedRealizedPnl = _owedRealizedPnlMap[trader]; _owedRealizedPnlMap[trader] = 0; return owedRealizedPnl; } /// @inheritdoc IAccountBalance function settleBalanceAndDeregister( address trader, address baseToken, int256 takerBase, int256 takerQuote, int256 realizedPnl, int256 makerFee ) external override { _requireOnlyClearingHouse(); _modifyTakerBalance(trader, baseToken, takerBase, takerQuote); _modifyOwedRealizedPnl(trader, makerFee); // @audit should merge _addOwedRealizedPnl and settleQuoteToOwedRealizedPnl in some way. // PnlRealized will be emitted three times when removing trader's liquidity _settleQuoteToOwedRealizedPnl(trader, baseToken, realizedPnl); _deregisterBaseToken(trader, baseToken); } /// @inheritdoc IAccountBalance function registerBaseToken(address trader, address baseToken) external override { _requireOnlyClearingHouse(); address[] storage tokensStorage = _baseTokensMap[trader]; if (_hasBaseToken(tokensStorage, baseToken)) { return; } tokensStorage.push(baseToken); // AB_MNE: markets number exceeds require(tokensStorage.length <= IClearingHouseConfig(_clearingHouseConfig).getMaxMarketsPerAccount(), "AB_MNE"); } /// @inheritdoc IAccountBalance function deregisterBaseToken(address trader, address baseToken) external override { _requireOnlyClearingHouse(); _deregisterBaseToken(trader, baseToken); } /// @inheritdoc IAccountBalance function updateTwPremiumGrowthGlobal( address trader, address baseToken, int256 lastTwPremiumGrowthGlobalX96 ) external override { _requireOnlyClearingHouse(); _accountMarketMap[trader][baseToken].lastTwPremiumGrowthGlobalX96 = lastTwPremiumGrowthGlobalX96; } /// @inheritdoc IAccountBalance /// @dev we don't do swap to get position notional here. /// we define the position notional in a closed market is `closed price * position size` function settlePositionInClosedMarket(address trader, address baseToken) external override returns ( int256 positionNotional, int256 openNotional, int256 realizedPnl, uint256 closedPrice ) { _requireOnlyClearingHouse(); int256 positionSize = getTakerPositionSize(trader, baseToken); closedPrice = IBaseToken(baseToken).getClosedPrice(); positionNotional = positionSize.mulDiv(closedPrice.toInt256(), 1e18); openNotional = _accountMarketMap[trader][baseToken].takerOpenNotional; realizedPnl = positionNotional.add(openNotional); _deleteBaseToken(trader, baseToken); _modifyOwedRealizedPnl(trader, realizedPnl); return (positionNotional, openNotional, realizedPnl, closedPrice); } // // EXTERNAL VIEW // /// @inheritdoc IAccountBalance function getClearingHouseConfig() external view override returns (address) { return _clearingHouseConfig; } /// @inheritdoc IAccountBalance function getOrderBook() external view override returns (address) { return _orderBook; } /// @inheritdoc IAccountBalance function getVault() external view override returns (address) { return _vault; } /// @inheritdoc IAccountBalance function getBaseTokens(address trader) external view override returns (address[] memory) { return _baseTokensMap[trader]; } /// @inheritdoc IAccountBalance function getAccountInfo(address trader, address baseToken) external view override returns (AccountMarket.Info memory) { return _accountMarketMap[trader][baseToken]; } // @inheritdoc IAccountBalance function getTakerOpenNotional(address trader, address baseToken) external view override returns (int256) { return _accountMarketMap[trader][baseToken].takerOpenNotional; } // @inheritdoc IAccountBalance function getTotalOpenNotional(address trader, address baseToken) external view override returns (int256) { // quote.pool[baseToken] + quoteBalance[baseToken] (uint256 quoteInPool, ) = IOrderBook(_orderBook).getTotalTokenAmountInPoolAndPendingFee(trader, baseToken, false); int256 quoteBalance = getQuote(trader, baseToken); return quoteInPool.toInt256().add(quoteBalance); } /// @inheritdoc IAccountBalance function getTotalDebtValue(address trader) external view override returns (uint256) { int256 totalQuoteBalance; int256 totalBaseDebtValue; uint256 tokenLen = _baseTokensMap[trader].length; for (uint256 i = 0; i < tokenLen; i++) { address baseToken = _baseTokensMap[trader][i]; int256 baseBalance = getBase(trader, baseToken); int256 baseDebtValue; // baseDebt = baseBalance when it's negative if (baseBalance < 0) { // baseDebtValue = baseDebt * indexPrice baseDebtValue = baseBalance.mulDiv(_getReferencePrice(baseToken).toInt256(), 1e18); } totalBaseDebtValue = totalBaseDebtValue.add(baseDebtValue); // we can't calculate totalQuoteDebtValue until we have totalQuoteBalance totalQuoteBalance = totalQuoteBalance.add(getQuote(trader, baseToken)); } int256 totalQuoteDebtValue = totalQuoteBalance >= 0 ? 0 : totalQuoteBalance; // both values are negative due to the above condition checks return totalQuoteDebtValue.add(totalBaseDebtValue).abs(); } /// @inheritdoc IAccountBalance function getPnlAndPendingFee(address trader) external view override returns ( int256, int256, uint256 ) { int256 totalPositionValue; uint256 tokenLen = _baseTokensMap[trader].length; for (uint256 i = 0; i < tokenLen; i++) { address baseToken = _baseTokensMap[trader][i]; totalPositionValue = totalPositionValue.add(getTotalPositionValue(trader, baseToken)); } (int256 netQuoteBalance, uint256 pendingFee) = _getNetQuoteBalanceAndPendingFee(trader); int256 unrealizedPnl = totalPositionValue.add(netQuoteBalance); return (_owedRealizedPnlMap[trader], unrealizedPnl, pendingFee); } /// @inheritdoc IAccountBalance function hasOrder(address trader) external view override returns (bool) { uint256 tokenLen = _baseTokensMap[trader].length; address[] memory tokens = new address[](tokenLen); uint256 skipped = 0; for (uint256 i = 0; i < tokenLen; i++) { address baseToken = _baseTokensMap[trader][i]; if (!IBaseToken(baseToken).isOpen()) { skipped++; continue; } tokens[i - skipped] = baseToken; } return IOrderBook(_orderBook).hasOrder(trader, tokens); } /// @inheritdoc IAccountBalance function getLiquidatablePositionSize( address trader, address baseToken, int256 accountValue ) external view override returns (int256) { int256 marginRequirement = getMarginRequirementForLiquidation(trader); int256 positionSize = getTotalPositionSize(trader, baseToken); // No liquidatable position if (accountValue >= marginRequirement || positionSize == 0) { return 0; } // Liquidate the entire position if its value is small enough // to prevent tiny positions left in the system uint256 positionValueAbs = _getPositionValue(baseToken, positionSize).abs(); if (positionValueAbs <= _MIN_PARTIAL_LIQUIDATE_POSITION_VALUE) { return positionSize; } // https://www.notion.so/perp/Backstop-LP-Spec-614b42798d4943768c2837bfe659524d#968996cadaec4c00ac60bd1da02ea8bb // Liquidator can only take over partial position if margin ratio is ≥ 3.125% (aka the half of mmRatio). // If margin ratio < 3.125%, liquidator can take over the entire position. // // threshold = mmRatio / 2 = 3.125% // if marginRatio >= threshold, then // maxLiquidateRatio = MIN(1, 0.5 * totalAbsPositionValue / absPositionValue) // if marginRatio < threshold, then // maxLiquidateRatio = 1 uint24 maxLiquidateRatio = 1e6; // 100% if (accountValue >= marginRequirement.div(2)) { // maxLiquidateRatio = getTotalAbsPositionValue / ( getTotalPositionValueInMarket.abs * 2 ) maxLiquidateRatio = FullMath .mulDiv(getTotalAbsPositionValue(trader), 1e6, positionValueAbs.mul(2)) .toUint24(); if (maxLiquidateRatio > 1e6) { maxLiquidateRatio = 1e6; } } return positionSize.mulRatio(maxLiquidateRatio); } /// @inheritdoc IAccountBalance function getMarkPrice(address baseToken) external view override returns (uint256) { return _getMarkPrice(baseToken); } // // PUBLIC VIEW // /// @inheritdoc IAccountBalance function getBase(address trader, address baseToken) public view override returns (int256) { uint256 orderDebt = IOrderBook(_orderBook).getTotalOrderDebt(trader, baseToken, true); // base = takerPositionSize - orderBaseDebt return _accountMarketMap[trader][baseToken].takerPositionSize.sub(orderDebt.toInt256()); } /// @inheritdoc IAccountBalance function getQuote(address trader, address baseToken) public view override returns (int256) { uint256 orderDebt = IOrderBook(_orderBook).getTotalOrderDebt(trader, baseToken, false); // quote = takerOpenNotional - orderQuoteDebt return _accountMarketMap[trader][baseToken].takerOpenNotional.sub(orderDebt.toInt256()); } /// @inheritdoc IAccountBalance function getTakerPositionSize(address trader, address baseToken) public view override returns (int256) { int256 positionSize = _accountMarketMap[trader][baseToken].takerPositionSize; return positionSize.abs() < _DUST ? 0 : positionSize; } /// @inheritdoc IAccountBalance function getTotalPositionSize(address trader, address baseToken) public view override returns (int256) { // NOTE: when a token goes into UniswapV3 pool (addLiquidity or swap), there would be 1 wei rounding error // for instance, maker adds liquidity with 2 base (2000000000000000000), // the actual base amount in pool would be 1999999999999999999 // makerBalance = totalTokenAmountInPool - totalOrderDebt (uint256 totalBaseBalanceFromOrders, ) = IOrderBook(_orderBook).getTotalTokenAmountInPoolAndPendingFee(trader, baseToken, true); uint256 totalBaseDebtFromOrder = IOrderBook(_orderBook).getTotalOrderDebt(trader, baseToken, true); int256 makerBaseBalance = totalBaseBalanceFromOrders.toInt256().sub(totalBaseDebtFromOrder.toInt256()); int256 takerPositionSize = _accountMarketMap[trader][baseToken].takerPositionSize; int256 totalPositionSize = makerBaseBalance.add(takerPositionSize); return totalPositionSize.abs() < _DUST ? 0 : totalPositionSize; } /// @inheritdoc IAccountBalance function getTotalPositionValue(address trader, address baseToken) public view override returns (int256) { int256 positionSize = getTotalPositionSize(trader, baseToken); return _getPositionValue(baseToken, positionSize); } /// @inheritdoc IAccountBalance function getTotalAbsPositionValue(address trader) public view override returns (uint256) { address[] memory tokens = _baseTokensMap[trader]; uint256 totalPositionValue; uint256 tokenLen = tokens.length; for (uint256 i = 0; i < tokenLen; i++) { address baseToken = tokens[i]; // will not use negative value in this case uint256 positionValue = getTotalPositionValue(trader, baseToken).abs(); totalPositionValue = totalPositionValue.add(positionValue); } return totalPositionValue; } /// @inheritdoc IAccountBalance function getMarginRequirementForLiquidation(address trader) public view override returns (int256) { return getTotalAbsPositionValue(trader) .mulRatio(IClearingHouseConfig(_clearingHouseConfig).getMmRatio()) .toInt256(); } // // INTERNAL NON-VIEW // function _modifyTakerBalance( address trader, address baseToken, int256 base, int256 quote ) internal returns (int256, int256) { AccountMarket.Info storage accountInfo = _accountMarketMap[trader][baseToken]; accountInfo.takerPositionSize = accountInfo.takerPositionSize.add(base); accountInfo.takerOpenNotional = accountInfo.takerOpenNotional.add(quote); return (accountInfo.takerPositionSize, accountInfo.takerOpenNotional); } function _modifyOwedRealizedPnl(address trader, int256 amount) internal { if (amount != 0) { _owedRealizedPnlMap[trader] = _owedRealizedPnlMap[trader].add(amount); emit PnlRealized(trader, amount); } } function _settleQuoteToOwedRealizedPnl( address trader, address baseToken, int256 amount ) internal { if (amount != 0) { AccountMarket.Info storage accountInfo = _accountMarketMap[trader][baseToken]; accountInfo.takerOpenNotional = accountInfo.takerOpenNotional.sub(amount); _modifyOwedRealizedPnl(trader, amount); } } /// @dev this function is expensive function _deregisterBaseToken(address trader, address baseToken) internal { AccountMarket.Info memory info = _accountMarketMap[trader][baseToken]; if (info.takerPositionSize.abs() >= _DUST || info.takerOpenNotional.abs() >= _DUST) { return; } if (IOrderBook(_orderBook).getOpenOrderIds(trader, baseToken).length > 0) { return; } _deleteBaseToken(trader, baseToken); } function _deleteBaseToken(address trader, address baseToken) internal { delete _accountMarketMap[trader][baseToken]; address[] storage tokensStorage = _baseTokensMap[trader]; uint256 tokenLen = tokensStorage.length; for (uint256 i; i < tokenLen; i++) { if (tokensStorage[i] == baseToken) { // if the target to be removed is the last one, pop it directly; // else, replace it with the last one and pop the last one instead if (i != tokenLen - 1) { tokensStorage[i] = tokensStorage[tokenLen - 1]; } tokensStorage.pop(); break; } } } // // INTERNAL VIEW // function _getPositionValue(address baseToken, int256 positionSize) internal view returns (int256) { if (positionSize == 0) return 0; uint256 price = _getReferencePrice(baseToken); // both positionSize & price are in 10^18 already // overflow inspection: // only overflow when position value in USD(18 decimals) > 2^255 / 10^18 return positionSize.mulDiv(price.toInt256(), 1e18); } function _getReferencePrice(address baseToken) internal view returns (uint256) { if (IBaseToken(baseToken).isOpen()) { return _getMarkPrice(baseToken); } return IBaseToken(baseToken).isClosed() ? IBaseToken(baseToken).getClosedPrice() : IBaseToken(baseToken).getPausedIndexPrice(); } /// @return netQuoteBalance = quote.balance + totalQuoteInPools function _getNetQuoteBalanceAndPendingFee(address trader) internal view returns (int256 netQuoteBalance, uint256 pendingFee) { int256 totalTakerQuoteBalance; uint256 tokenLen = _baseTokensMap[trader].length; for (uint256 i = 0; i < tokenLen; i++) { address baseToken = _baseTokensMap[trader][i]; totalTakerQuoteBalance = totalTakerQuoteBalance.add(_accountMarketMap[trader][baseToken].takerOpenNotional); } // pendingFee is included int256 totalMakerQuoteBalance; (totalMakerQuoteBalance, pendingFee) = IOrderBook(_orderBook).getTotalQuoteBalanceAndPendingFee( trader, _baseTokensMap[trader] ); netQuoteBalance = totalTakerQuoteBalance.add(totalMakerQuoteBalance); return (netQuoteBalance, pendingFee); } function _getMarkPrice(address baseToken) internal view virtual returns (uint256) { IClearingHouseConfig clearingHouseConfig = IClearingHouseConfig(_clearingHouseConfig); (uint32 marketTwapInterval, uint32 premiumInterval) = clearingHouseConfig.getMarkPriceConfig(); uint256 marketPrice = _getMarketPrice(baseToken, 0); uint256 marketTwap = _getMarketPrice(baseToken, marketTwapInterval); int256 premium = _getMarketPrice(baseToken, premiumInterval).toInt256().sub( _getIndexPrice(baseToken, premiumInterval).toInt256() ); uint256 indexWithPremium = _getIndexPrice(baseToken, 0).toInt256().add(premium).toUint256(); return PerpMath.findMedianOfThree(marketPrice, marketTwap, indexWithPremium); } function _getMarketPrice(address baseToken, uint32 twapInterval) internal view returns (uint256) { return IExchange(IOrderBook(_orderBook).getExchange()) .getSqrtMarketTwapX96(baseToken, twapInterval) .formatSqrtPriceX96ToPriceX96() .formatX96ToX10_18(); } function _getIndexPrice(address baseToken, uint32 twapInterval) internal view returns (uint256) { return IIndexPrice(baseToken).getIndexPrice(twapInterval); } // // INTERNAL PURE // function _hasBaseToken(address[] memory baseTokens, address baseToken) internal pure returns (bool) { for (uint256 i = 0; i < baseTokens.length; i++) { if (baseTokens[i] == baseToken) { return true; } } return false; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMathUpgradeable { int256 constant private _INT256_MIN = -2**255; /** * @dev Returns the multiplication of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two signed integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Returns the subtraction of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Returns the addition of two signed integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } }
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; 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 a proxied contract can't have 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. * * 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 {UpgradeableProxy-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. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @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 * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../proxy/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 GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.4.0; /// @title FixedPoint96 /// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format) /// @dev Used in SqrtPriceMath.sol library FixedPoint96 { uint8 internal constant RESOLUTION = 96; uint256 internal constant Q96 = 0x1000000000000000000000000; }
// SPDX-License-Identifier: MIT pragma solidity >=0.4.0; /// @title Contains 512-bit math functions /// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision /// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { // 512-bit multiply [prod1 prod0] = a * b // Compute the product mod 2**256 and mod 2**256 - 1 // then use the Chinese Remainder Theorem to reconstruct // the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2**256 + prod0 uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256. // Also prevents denominator == 0 require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] // Compute remainder using mulmod uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator // Compute largest power of two divisor of denominator. // Always >= 1. uint256 twos = -denominator & denominator; // Divide denominator by power of two assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos. // If twos is zero, then it becomes one assembly { twos := add(div(sub(0, twos), twos), 1) } prod0 |= prod1 * twos; // Invert denominator mod 2**256 // Now that denominator is an odd number, it has an inverse // modulo 2**256 such that denominator * inv = 1 mod 2**256. // Compute the inverse by starting with a seed that is correct // correct for four bits. That is, denominator * inv = 1 mod 2**4 uint256 inv = (3 * denominator) ^ 2; // Now use Newton-Raphson iteration to improve the precision. // Thanks to Hensel's lifting lemma, this also works in modular // arithmetic, doubling the correct bits in each step. inv *= 2 - denominator * inv; // inverse mod 2**8 inv *= 2 - denominator * inv; // inverse mod 2**16 inv *= 2 - denominator * inv; // inverse mod 2**32 inv *= 2 - denominator * inv; // inverse mod 2**64 inv *= 2 - denominator * inv; // inverse mod 2**128 inv *= 2 - denominator * inv; // inverse mod 2**256 // Because the division is now exact we can divide by multiplying // with the modular inverse of denominator. This will give us the // correct result modulo 2**256. Since the precoditions guarantee // that the outcome is less than 2**256, this is the final result. // We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inv; return result; } /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 /// @param a The multiplicand /// @param b The multiplier /// @param denominator The divisor /// @return result The 256-bit result function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); if (mulmod(a, b, denominator) > 0) { require(result < type(uint256).max); result++; } } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; /// @title Math library for computing sqrt prices from ticks and vice versa /// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports /// prices between 2**-128 and 2**128 library TickMath { /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128 int24 internal constant MIN_TICK = -887272; /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128 int24 internal constant MAX_TICK = -MIN_TICK; /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK) uint160 internal constant MIN_SQRT_RATIO = 4295128739; /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK) uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342; /// @notice Calculates sqrt(1.0001^tick) * 2^96 /// @dev Throws if |tick| > max tick /// @param tick The input tick for the above formula /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0) /// at the given tick function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) { uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick)); require(absTick <= uint256(MAX_TICK), 'T'); uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000; if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128; if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128; if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128; if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128; if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128; if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128; if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128; if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128; if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128; if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128; if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128; if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128; if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128; if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128; if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128; if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128; if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128; if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128; if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128; if (tick > 0) ratio = type(uint256).max / ratio; // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96. // we then downcast because we know the result always fits within 160 bits due to our tick input constraint // we round up in the division so getTickAtSqrtRatio of the output price is always consistent sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)); } /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may /// ever return. /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96 /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) { // second inequality must be < because the price can never reach the price at the max tick require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R'); uint256 ratio = uint256(sqrtPriceX96) << 32; uint256 r = ratio; uint256 msb = 0; assembly { let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(5, gt(r, 0xFFFFFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(4, gt(r, 0xFFFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(3, gt(r, 0xFF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(2, gt(r, 0xF)) msb := or(msb, f) r := shr(f, r) } assembly { let f := shl(1, gt(r, 0x3)) msb := or(msb, f) r := shr(f, r) } assembly { let f := gt(r, 0x1) msb := or(msb, f) } if (msb >= 128) r = ratio >> (msb - 127); else r = ratio << (127 - msb); int256 log_2 = (int256(msb) - 128) << 64; assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(63, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(62, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(61, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(60, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(59, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(58, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(57, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(56, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(55, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(54, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(53, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(52, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(51, f)) r := shr(f, r) } assembly { r := shr(127, mul(r, r)) let f := shr(128, r) log_2 := or(log_2, shl(50, f)) } int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128); int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128); tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.5.0; import '@uniswap/v3-core/contracts/libraries/FullMath.sol'; import '@uniswap/v3-core/contracts/libraries/FixedPoint96.sol'; /// @title Liquidity amount functions /// @notice Provides functions for computing liquidity amounts from token amounts and prices library LiquidityAmounts { /// @notice Downcasts uint256 to uint128 /// @param x The uint258 to be downcasted /// @return y The passed value, downcasted to uint128 function toUint128(uint256 x) private pure returns (uint128 y) { require((y = uint128(x)) == x); } /// @notice Computes the amount of liquidity received for a given amount of token0 and price range /// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)) /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount0 The amount0 being sent in /// @return liquidity The amount of returned liquidity function getLiquidityForAmount0( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); uint256 intermediate = FullMath.mulDiv(sqrtRatioAX96, sqrtRatioBX96, FixedPoint96.Q96); return toUint128(FullMath.mulDiv(amount0, intermediate, sqrtRatioBX96 - sqrtRatioAX96)); } /// @notice Computes the amount of liquidity received for a given amount of token1 and price range /// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)). /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount1 The amount1 being sent in /// @return liquidity The amount of returned liquidity function getLiquidityForAmount1( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount1 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return toUint128(FullMath.mulDiv(amount1, FixedPoint96.Q96, sqrtRatioBX96 - sqrtRatioAX96)); } /// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current /// pool prices and the prices at the tick boundaries /// @param sqrtRatioX96 A sqrt price representing the current pool prices /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param amount0 The amount of token0 being sent in /// @param amount1 The amount of token1 being sent in /// @return liquidity The maximum amount of liquidity received function getLiquidityForAmounts( uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint256 amount0, uint256 amount1 ) internal pure returns (uint128 liquidity) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { liquidity = getLiquidityForAmount0(sqrtRatioAX96, sqrtRatioBX96, amount0); } else if (sqrtRatioX96 < sqrtRatioBX96) { uint128 liquidity0 = getLiquidityForAmount0(sqrtRatioX96, sqrtRatioBX96, amount0); uint128 liquidity1 = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioX96, amount1); liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1; } else { liquidity = getLiquidityForAmount1(sqrtRatioAX96, sqrtRatioBX96, amount1); } } /// @notice Computes the amount of token0 for a given amount of liquidity and a price range /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount0 The amount of token0 function getAmount0ForLiquidity( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv( uint256(liquidity) << FixedPoint96.RESOLUTION, sqrtRatioBX96 - sqrtRatioAX96, sqrtRatioBX96 ) / sqrtRatioAX96; } /// @notice Computes the amount of token1 for a given amount of liquidity and a price range /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount1 The amount of token1 function getAmount1ForLiquidity( uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); return FullMath.mulDiv(liquidity, sqrtRatioBX96 - sqrtRatioAX96, FixedPoint96.Q96); } /// @notice Computes the token0 and token1 value for a given amount of liquidity, the current /// pool prices and the prices at the tick boundaries /// @param sqrtRatioX96 A sqrt price representing the current pool prices /// @param sqrtRatioAX96 A sqrt price representing the first tick boundary /// @param sqrtRatioBX96 A sqrt price representing the second tick boundary /// @param liquidity The liquidity being valued /// @return amount0 The amount of token0 /// @return amount1 The amount of token1 function getAmountsForLiquidity( uint160 sqrtRatioX96, uint160 sqrtRatioAX96, uint160 sqrtRatioBX96, uint128 liquidity ) internal pure returns (uint256 amount0, uint256 amount1) { if (sqrtRatioAX96 > sqrtRatioBX96) (sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96); if (sqrtRatioX96 <= sqrtRatioAX96) { amount0 = getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } else if (sqrtRatioX96 < sqrtRatioBX96) { amount0 = getAmount0ForLiquidity(sqrtRatioX96, sqrtRatioBX96, liquidity); amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioX96, liquidity); } else { amount1 = getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity); } } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; abstract contract BlockContext { function _blockTimestamp() internal view virtual returns (uint256) { // Reply from Arbitrum // block.timestamp returns timestamp at the time at which the sequencer receives the tx. // It may not actually correspond to a particular L1 block return block.timestamp; } function _blockNumber() internal view virtual returns (uint256) { return block.number; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; pragma abicoder v2; import { SafeOwnable } from "./SafeOwnable.sol"; abstract contract ClearingHouseCallee is SafeOwnable { // // STATE // address internal _clearingHouse; // __gap is reserved storage uint256[50] private __gap; // // EVENT // event ClearingHouseChanged(address indexed clearingHouse); // // CONSTRUCTOR // // solhint-disable-next-line func-order function __ClearingHouseCallee_init() internal initializer { __SafeOwnable_init(); } function setClearingHouse(address clearingHouseArg) external onlyOwner { _clearingHouse = clearingHouseArg; emit ClearingHouseChanged(clearingHouseArg); } function getClearingHouse() external view returns (address) { return _clearingHouse; } function _requireOnlyClearingHouse() internal view { // only ClearingHouse require(_msgSender() == _clearingHouse, "CHD_OCH"); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; import { ContextUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol"; abstract contract SafeOwnable is ContextUpgradeable { address private _owner; address private _candidate; // __gap is reserved storage uint256[50] private __gap; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { // caller not owner require(owner() == _msgSender(), "SO_CNO"); _; } /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __SafeOwnable_init() internal initializer { __Context_init(); address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() external virtual onlyOwner { // emitting event first to avoid caching values emit OwnershipTransferred(_owner, address(0)); _owner = address(0); _candidate = address(0); } /** * @dev Set ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function setOwner(address newOwner) external onlyOwner { // newOwner is 0 require(newOwner != address(0), "SO_NW0"); // same as original require(newOwner != _owner, "SO_SAO"); // same as candidate require(newOwner != _candidate, "SO_SAC"); _candidate = newOwner; } /** * @dev Transfers ownership of the contract to a new account (`_candidate`). * Can only be called by the new owner. */ function updateOwner() external { // candidate is zero require(_candidate != address(0), "SO_C0"); // caller is not candidate require(_candidate == _msgSender(), "SO_CNC"); // emitting event first to avoid caching values emit OwnershipTransferred(_owner, _candidate); _owner = _candidate; _candidate = address(0); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Returns the candidate that can become the owner. */ function candidate() external view returns (address) { return _candidate; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; pragma abicoder v2; import { AccountMarket } from "../lib/AccountMarket.sol"; interface IAccountBalance { /// @param vault The address of the vault contract event VaultChanged(address indexed vault); /// @dev Emit whenever a trader's `owedRealizedPnl` is updated /// @param trader The address of the trader /// @param amount The amount changed event PnlRealized(address indexed trader, int256 amount); /// @notice Modify trader account balance /// @dev Only used by `ClearingHouse` contract /// @param trader The address of the trader /// @param baseToken The address of the baseToken /// @param base Modified amount of base /// @param quote Modified amount of quote /// @return takerPositionSize Taker position size after modified /// @return takerOpenNotional Taker open notional after modified function modifyTakerBalance( address trader, address baseToken, int256 base, int256 quote ) external returns (int256 takerPositionSize, int256 takerOpenNotional); /// @notice Modify trader owedRealizedPnl /// @dev Only used by `ClearingHouse` contract /// @param trader The address of the trader /// @param amount Modified amount of owedRealizedPnl function modifyOwedRealizedPnl(address trader, int256 amount) external; /// @notice Settle owedRealizedPnl /// @dev Only used by `Vault.withdraw()` /// @param trader The address of the trader /// @return pnl Settled owedRealizedPnl function settleOwedRealizedPnl(address trader) external returns (int256 pnl); /// @notice Modify trader owedRealizedPnl /// @dev Only used by `ClearingHouse` contract /// @param trader The address of the trader /// @param baseToken The address of the baseToken /// @param amount Settled quote amount function settleQuoteToOwedRealizedPnl( address trader, address baseToken, int256 amount ) external; /// @notice Settle account balance and deregister base token /// @dev Only used by `ClearingHouse` contract /// @param trader The address of the trader /// @param baseToken The address of the baseToken /// @param takerBase Modified amount of taker base /// @param takerQuote Modified amount of taker quote /// @param realizedPnl Amount of pnl realized /// @param makerFee Amount of maker fee collected from pool function settleBalanceAndDeregister( address trader, address baseToken, int256 takerBase, int256 takerQuote, int256 realizedPnl, int256 makerFee ) external; /// @notice Every time a trader's position value is checked, the base token list of this trader will be traversed; /// thus, this list should be kept as short as possible /// @dev Only used by `ClearingHouse` contract /// @param trader The address of the trader /// @param baseToken The address of the trader's base token function registerBaseToken(address trader, address baseToken) external; /// @notice Deregister baseToken from trader accountInfo /// @dev Only used by `ClearingHouse` contract, this function is expensive, due to for loop /// @param trader The address of the trader /// @param baseToken The address of the trader's base token function deregisterBaseToken(address trader, address baseToken) external; /// @notice Update trader Twap premium info /// @dev Only used by `ClearingHouse` contract /// @param trader The address of trader /// @param baseToken The address of baseToken /// @param lastTwPremiumGrowthGlobalX96 The last Twap Premium function updateTwPremiumGrowthGlobal( address trader, address baseToken, int256 lastTwPremiumGrowthGlobalX96 ) external; /// @notice Settle trader's PnL in closed market /// @dev Only used by `ClearingHouse` /// @param trader The address of the trader /// @param baseToken The address of the trader's base token /// @return positionNotional Taker's position notional settled with closed price /// @return openNotional Taker's open notional /// @return realizedPnl Settled realized pnl /// @return closedPrice The closed price of the closed market function settlePositionInClosedMarket(address trader, address baseToken) external returns ( int256 positionNotional, int256 openNotional, int256 realizedPnl, uint256 closedPrice ); /// @notice Get `ClearingHouseConfig` address /// @return clearingHouseConfig The address of ClearingHouseConfig function getClearingHouseConfig() external view returns (address clearingHouseConfig); /// @notice Get `OrderBook` address /// @return orderBook The address of OrderBook function getOrderBook() external view returns (address orderBook); /// @notice Get `Vault` address /// @return vault The address of Vault function getVault() external view returns (address vault); /// @notice Get trader registered baseTokens /// @param trader The address of trader /// @return baseTokens The array of baseToken address function getBaseTokens(address trader) external view returns (address[] memory baseTokens); /// @notice Get trader account info /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return traderAccountInfo The baseToken account info of trader function getAccountInfo(address trader, address baseToken) external view returns (AccountMarket.Info memory traderAccountInfo); /// @notice Get taker cost of trader's baseToken /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return openNotional The taker cost of trader's baseToken function getTakerOpenNotional(address trader, address baseToken) external view returns (int256 openNotional); /// @notice Get total cost of trader's baseToken /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return totalOpenNotional the amount of quote token paid for a position when opening function getTotalOpenNotional(address trader, address baseToken) external view returns (int256 totalOpenNotional); /// @notice Get total debt value of trader /// @param trader The address of trader /// @dev Total debt value will relate to `Vault.getFreeCollateral()` /// @return totalDebtValue The debt value of trader function getTotalDebtValue(address trader) external view returns (uint256 totalDebtValue); /// @notice Get margin requirement to check whether trader will be able to liquidate /// @dev This is different from `Vault._getTotalMarginRequirement()`, which is for freeCollateral calculation /// @param trader The address of trader /// @return marginRequirementForLiquidation It is compared with `ClearingHouse.getAccountValue` which is also an int function getMarginRequirementForLiquidation(address trader) external view returns (int256 marginRequirementForLiquidation); /// @notice Get owedRealizedPnl, unrealizedPnl and pending fee /// @param trader The address of trader /// @return owedRealizedPnl the pnl realized already but stored temporarily in AccountBalance /// @return unrealizedPnl the pnl not yet realized /// @return pendingFee the pending fee of maker earned function getPnlAndPendingFee(address trader) external view returns ( int256 owedRealizedPnl, int256 unrealizedPnl, uint256 pendingFee ); /// @notice Check trader has open order in open/closed market. /// @param trader The address of trader /// @return True of false function hasOrder(address trader) external view returns (bool); /// @notice Get trader base amount /// @dev `base amount = takerPositionSize - orderBaseDebt` /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return baseAmount The base amount of trader's baseToken market function getBase(address trader, address baseToken) external view returns (int256 baseAmount); /// @notice Get trader quote amount /// @dev `quote amount = takerOpenNotional - orderQuoteDebt` /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return quoteAmount The quote amount of trader's baseToken market function getQuote(address trader, address baseToken) external view returns (int256 quoteAmount); /// @notice Get taker position size of trader's baseToken market /// @dev This will only has taker position, can get maker impermanent position through `getTotalPositionSize` /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return takerPositionSize The taker position size of trader's baseToken market function getTakerPositionSize(address trader, address baseToken) external view returns (int256 takerPositionSize); /// @notice Get total position size of trader's baseToken market /// @dev `total position size = taker position size + maker impermanent position size` /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return totalPositionSize The total position size of trader's baseToken market function getTotalPositionSize(address trader, address baseToken) external view returns (int256 totalPositionSize); /// @notice Get total position value of trader's baseToken market /// @dev A negative returned value is only be used when calculating pnl, /// @dev we use mark price to calc position value /// @param trader The address of trader /// @param baseToken The address of baseToken /// @return totalPositionValue Total position value of trader's baseToken market function getTotalPositionValue(address trader, address baseToken) external view returns (int256 totalPositionValue); /// @notice Get all market position abs value of trader /// @param trader The address of trader /// @return totalAbsPositionValue Sum up positions value of every market function getTotalAbsPositionValue(address trader) external view returns (uint256 totalAbsPositionValue); /// @notice Get liquidatable position size of trader's baseToken market /// @param trader The address of trader /// @param baseToken The address of baseToken /// @param accountValue The account value of trader /// @return liquidatablePositionSize The liquidatable position size of trader's baseToken market function getLiquidatablePositionSize( address trader, address baseToken, int256 accountValue ) external view returns (int256); /// @notice Get mark price of baseToken market /// @dev Mark price is the median of three prices as below. /// 1. current market price /// 2. market twap with 30 mins /// 3. index price + premium with 15 mins /// @dev If the parameters to calculate mark price are not set, returns index twap instead for backward compatible /// @dev If the market is paused, returns index twap instead, that will be the index twap while pausing market /// @param baseToken The address of baseToken /// @return price The mark price of baseToken market function getMarkPrice(address baseToken) external view returns (uint256); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; interface IBaseToken { // Do NOT change the order of enum values because it will break backwards compatibility enum Status { Open, Paused, Closed } event PriceFeedChanged(address indexed priceFeed); event StatusUpdated(Status indexed status); function close() external; /// @notice Update the cached index price of the token. /// @param interval The twap interval in seconds. function cacheTwap(uint256 interval) external; /// @notice Get the price feed address /// @dev priceFeed is now priceFeedDispatcher, which dispatches either Chainlink or UniswapV3 price /// @return priceFeed the current price feed function getPriceFeed() external view returns (address priceFeed); function getPausedTimestamp() external view returns (uint256); function getPausedIndexPrice() external view returns (uint256); function getClosedPrice() external view returns (uint256); function isOpen() external view returns (bool); function isPaused() external view returns (bool); function isClosed() external view returns (bool); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; interface IClearingHouseConfigEvent { event LiquidationPenaltyRatioChanged(uint24 liquidationPenaltyRatio); event PartialCloseRatioChanged(uint24 partialCloseRatio); event TwapIntervalChanged(uint256 twapInterval); event MaxMarketsPerAccountChanged(uint8 maxMarketsPerAccount); event SettlementTokenBalanceCapChanged(uint256 cap); event MaxFundingRateChanged(uint24 rate); event MarkPriceMarketTwapIntervalChanged(uint32 twapInterval); event MarkPricePremiumIntervalChanged(uint32 premiumInterval); } interface IClearingHouseConfig is IClearingHouseConfigEvent { /// @return maxMarketsPerAccount Max value of total markets per account function getMaxMarketsPerAccount() external view returns (uint8 maxMarketsPerAccount); /// @return imRatio Initial margin ratio function getImRatio() external view returns (uint24 imRatio); /// @return mmRatio Maintenance margin requirement ratio function getMmRatio() external view returns (uint24 mmRatio); /// @return liquidationPenaltyRatio Liquidation penalty ratio function getLiquidationPenaltyRatio() external view returns (uint24 liquidationPenaltyRatio); /// @notice **Deprecated function, will be removed in later release** /// @return partialCloseRatio Partial close ratio function getPartialCloseRatio() external view returns (uint24 partialCloseRatio); /// @return twapInterval TwapInterval for funding and prices (market & index) calculations function getTwapInterval() external view returns (uint32 twapInterval); /// @return settlementTokenBalanceCap Max value of settlement token balance function getSettlementTokenBalanceCap() external view returns (uint256 settlementTokenBalanceCap); /// @return maxFundingRate Max value of funding rate function getMaxFundingRate() external view returns (uint24 maxFundingRate); /// @return marketTwapInterval MarketTwapInterval is the interval of market twap used for mark price calculations /// @return premiumInterval PremiumInterval is the interval of premium used for mark price calculations function getMarkPriceConfig() external view returns (uint32 marketTwapInterval, uint32 premiumInterval); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; pragma abicoder v2; import { Funding } from "../lib/Funding.sol"; interface IExchange { /// @param amount when closing position, amount(uint256) == takerPositionSize(int256), /// as amount is assigned as takerPositionSize in ClearingHouse.closePosition() struct SwapParams { address trader; address baseToken; bool isBaseToQuote; bool isExactInput; bool isClose; uint256 amount; uint160 sqrtPriceLimitX96; } struct SwapResponse { uint256 base; uint256 quote; int256 exchangedPositionSize; int256 exchangedPositionNotional; uint256 fee; uint256 insuranceFundFee; int256 pnlToBeRealized; uint256 sqrtPriceAfterX96; int24 tick; bool isPartialClose; uint24 closedRatio; } struct SwapCallbackData { address trader; address baseToken; address pool; uint24 uniswapFeeRatio; uint256 fee; } struct RealizePnlParams { address trader; address baseToken; int256 base; int256 quote; } /// @notice Emitted when the global funding growth is updated /// @param baseToken Address of the base token /// @param marketTwap The market twap price when the funding growth is updated /// @param indexTwap The index twap price when the funding growth is updated event FundingUpdated(address indexed baseToken, uint256 marketTwap, uint256 indexTwap); /// @notice Emitted when maxTickCrossedWithinBlock is updated /// @param baseToken Address of the base token /// @param maxTickCrossedWithinBlock Max tick allowed to be crossed within block when reducing position event MaxTickCrossedWithinBlockChanged(address indexed baseToken, uint24 maxTickCrossedWithinBlock); /// @notice Emitted when accountBalance is updated /// @param accountBalance The address of accountBalance contract event AccountBalanceChanged(address accountBalance); /// @notice The actual swap function /// @dev can only be called from ClearingHouse /// @param params The parameters of the swap /// @return swapResponse The result of the swap function swap(SwapParams memory params) external returns (SwapResponse memory swapResponse); /// @notice Settle the funding payment for the time interval since the last settlement /// @dev This function should be called at the beginning of every high-level function, such as `openPosition()` /// while it doesn't matter who calls this function /// this function 1. settles personal funding payment 2. updates global funding growth /// personal funding payment is settled whenever there is pending funding payment /// the global funding growth update only happens once per unique timestamp (not blockNumber, due to Arbitrum) /// @return fundingPayment the funding payment of a trader in one market should be settled into owned realized Pnl /// @return fundingGrowthGlobal the up-to-date globalFundingGrowth, usually used for later calculations function settleFunding(address trader, address baseToken) external returns (int256 fundingPayment, Funding.Growth memory fundingGrowthGlobal); /// @notice Get the max ticks allowed to be crossed within a block when reducing position /// @param baseToken Address of the base token /// @return maxTickCrossedWithinBlock The max ticks allowed to be crossed within a block when reducing position function getMaxTickCrossedWithinBlock(address baseToken) external view returns (uint24 maxTickCrossedWithinBlock); /// @notice Get all the pending funding payment for a trader /// @return pendingFundingPayment The pending funding payment of the trader. /// Positive value means the trader pays funding, negative value means the trader receives funding. function getAllPendingFundingPayment(address trader) external view returns (int256 pendingFundingPayment); /// @notice Check if current price spread between market price and index twap is over maximum price spread. /// @param baseToken Address of the base token /// @return true if over the maximum price spread function isOverPriceSpread(address baseToken) external view returns (bool); /// @notice Get the pending funding payment for a trader in a given market /// @dev this is the view version of _updateFundingGrowth() /// @return pendingFundingPayment The pending funding payment of a trader in one market, /// including liquidity & balance coefficients. Positive value means the trader pays funding, /// negative value means the trader receives funding. function getPendingFundingPayment(address trader, address baseToken) external view returns (int256 pendingFundingPayment); /// @notice **Deprecated function, will be removed in the next release, use `getSqrtMarketTwapX96()` instead** /// Get the square root of the market twap price with the given time interval /// @dev The return value is a X96 number /// @param baseToken Address of the base token /// @param twapInterval The time interval in seconds /// @return sqrtMarkTwapX96 The square root of the market twap price function getSqrtMarkTwapX96(address baseToken, uint32 twapInterval) external view returns (uint160 sqrtMarkTwapX96); /// @notice Get the square root of the market twap price with the given time interval /// @dev The return value is a X96 number /// @param baseToken Address of the base token /// @param twapInterval The time interval in seconds /// @return sqrtMarketTwapX96 The square root of the market twap price function getSqrtMarketTwapX96(address baseToken, uint32 twapInterval) external view returns (uint160 sqrtMarketTwapX96); /// @notice Get the pnl that can be realized if trader reduce position /// @dev This function normally won't be needed by traders, but it might be useful for 3rd party /// @param params The params needed to do the query, encoded as `RealizePnlParams` in calldata /// @return pnlToBeRealized The pnl that can be realized if trader reduce position function getPnlToBeRealized(RealizePnlParams memory params) external view returns (int256 pnlToBeRealized); /// @notice Get `OrderBook` contract address /// @return orderBook `OrderBook` contract address function getOrderBook() external view returns (address orderBook); /// @notice Get `AccountBalance` contract address /// @return accountBalance `AccountBalance` contract address function getAccountBalance() external view returns (address accountBalance); /// @notice Get `ClearingHouseConfig` contract address /// @return clearingHouse `ClearingHouseConfig` contract address function getClearingHouseConfig() external view returns (address clearingHouse); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; interface IIndexPrice { /// @notice Returns the index price of the token. /// @param interval The interval represents twap interval. /// @return indexPrice Twap price with interval function getIndexPrice(uint256 interval) external view returns (uint256 indexPrice); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; pragma abicoder v2; import { Funding } from "../lib/Funding.sol"; import { OpenOrder } from "../lib/OpenOrder.sol"; interface IOrderBook { struct AddLiquidityParams { address trader; address baseToken; uint256 base; uint256 quote; int24 lowerTick; int24 upperTick; Funding.Growth fundingGrowthGlobal; } struct RemoveLiquidityParams { address maker; address baseToken; int24 lowerTick; int24 upperTick; uint128 liquidity; } struct AddLiquidityResponse { uint256 base; uint256 quote; uint256 fee; uint128 liquidity; } struct RemoveLiquidityResponse { uint256 base; uint256 quote; uint256 fee; int256 takerBase; int256 takerQuote; } struct ReplaySwapParams { address baseToken; bool isBaseToQuote; bool shouldUpdateState; int256 amount; uint160 sqrtPriceLimitX96; uint24 exchangeFeeRatio; uint24 uniswapFeeRatio; Funding.Growth globalFundingGrowth; address pool; uint24 insuranceFundFeeRatio; } /// @param insuranceFundFee = fee * insuranceFundFeeRatio struct ReplaySwapResponse { int24 tick; uint256 fee; uint256 insuranceFundFee; } struct MintCallbackData { address trader; address pool; } /// @notice Emitted when the `Exchange` contract address changed /// @param exchange The address of exchange contract event ExchangeChanged(address indexed exchange); /// @notice Add liquidity logic /// @dev Only used by `ClearingHouse` contract /// @param params Add liquidity params, detail on `IOrderBook.AddLiquidityParams` /// @return response Add liquidity response, detail on `IOrderBook.AddLiquidityResponse` function addLiquidity(AddLiquidityParams calldata params) external returns (AddLiquidityResponse memory response); /// @notice Remove liquidity logic, only used by `ClearingHouse` contract /// @param params Remove liquidity params, detail on `IOrderBook.RemoveLiquidityParams` /// @return response Remove liquidity response, detail on `IOrderBook.RemoveLiquidityResponse` function removeLiquidity(RemoveLiquidityParams calldata params) external returns (RemoveLiquidityResponse memory response); /// @dev This is the non-view version of `getLiquidityCoefficientInFundingPayment()`, /// only can be called by `Exchange` contract /// @param trader The trader address /// @param baseToken The base token address /// @param fundingGrowthGlobal The funding growth info, detail on `Funding.Growth` /// @return liquidityCoefficientInFundingPayment the funding payment of all orders/liquidity of a maker function updateFundingGrowthAndLiquidityCoefficientInFundingPayment( address trader, address baseToken, Funding.Growth memory fundingGrowthGlobal ) external returns (int256 liquidityCoefficientInFundingPayment); /// @notice Replay the swap and get the swap result (price impact and swap fee), /// only can be called by `Exchange` contract; /// @dev `ReplaySwapResponse.insuranceFundFee = fee * insuranceFundFeeRatio` /// @param params ReplaySwap params, detail on `IOrderBook.ReplaySwapParams` /// @return response The swap result encoded in `ReplaySwapResponse` function replaySwap(ReplaySwapParams memory params) external returns (ReplaySwapResponse memory response); function updateOrderDebt( bytes32 orderId, int256 base, int256 quote ) external; /// @notice Get open order ids of a trader in the given market /// @param trader The trader address /// @param baseToken The base token address /// @return orderIds The open order ids function getOpenOrderIds(address trader, address baseToken) external view returns (bytes32[] memory orderIds); /// @notice Get open order info by given order id /// @param orderId The order id /// @return info The open order info encoded in `OpenOrder.Info` function getOpenOrderById(bytes32 orderId) external view returns (OpenOrder.Info memory info); /// @notice Get open order info by given base token, upper tick and lower tick /// @param trader The trader address /// @param baseToken The base token address /// @param upperTick The upper tick /// @param lowerTick The lower tick /// @return info he open order info encoded in `OpenOrder.Info` function getOpenOrder( address trader, address baseToken, int24 lowerTick, int24 upperTick ) external view returns (OpenOrder.Info memory info); /// @notice Check if the specified trader has order in given markets /// @param trader The trader address /// @param tokens The base token addresses /// @return hasOrder True if the trader has order in given markets function hasOrder(address trader, address[] calldata tokens) external view returns (bool hasOrder); /// @notice Get the total quote token amount and pending fees of all orders in given markets /// @param trader The trader address /// @param baseTokens The base token addresses /// @return totalQuoteAmountInPools The total quote token amount /// @return totalPendingFee The total pending fees in the orders function getTotalQuoteBalanceAndPendingFee(address trader, address[] calldata baseTokens) external view returns (int256 totalQuoteAmountInPools, uint256 totalPendingFee); /// @notice Get the total token amount (quote or base) and pending fees of all orders in the given market /// @param trader The trader address /// @param baseToken The base token addresses /// @param fetchBase True if fetch base token amount, false if fetch quote token amount /// @return tokenAmount The total quote/base token amount /// @return totalPendingFee The total pending fees in the orders function getTotalTokenAmountInPoolAndPendingFee( address trader, address baseToken, bool fetchBase ) external view returns (uint256 tokenAmount, uint256 totalPendingFee); /// @notice Get the total debt token amount (base or quote) of all orders in the given market /// @param trader The trader address /// @param baseToken The base token address /// @param fetchBase True if fetch base token amount, false if fetch quote token amount /// @return debtAmount The total debt token amount function getTotalOrderDebt( address trader, address baseToken, bool fetchBase ) external view returns (uint256 debtAmount); /// @notice Get the pending funding payment of all orders in the given market /// @dev This is the view version of `updateFundingGrowthAndLiquidityCoefficientInFundingPayment()`, so only /// part of the funding payment will be returned. Use it with caution because it does not return all the pending /// funding payment of orders. **Normally you won't need to use this function** /// @return liquidityCoefficientInFundingPayment the funding payment of all orders/liquidity of a maker function getLiquidityCoefficientInFundingPayment( address trader, address baseToken, Funding.Growth memory fundingGrowthGlobal ) external view returns (int256 liquidityCoefficientInFundingPayment); /// @notice Get the pending fees of a order /// @param trader The trader address /// @param baseToken The base token address /// @param lowerTick The lower tick /// @param upperTick The upper tick /// @return fee The pending fees function getPendingFee( address trader, address baseToken, int24 lowerTick, int24 upperTick ) external view returns (uint256 fee); /// @notice Get `Exchange` contract address /// @return exchange The `Exchange` contract address function getExchange() external view returns (address exchange); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; library AccountMarket { /// @param lastTwPremiumGrowthGlobalX96 the last time weighted premiumGrowthGlobalX96 struct Info { int256 takerPositionSize; int256 takerOpenNotional; int256 lastTwPremiumGrowthGlobalX96; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; import { Tick } from "./Tick.sol"; import { PerpMath } from "./PerpMath.sol"; import { OpenOrder } from "./OpenOrder.sol"; import { PerpSafeCast } from "./PerpSafeCast.sol"; import { PerpFixedPoint96 } from "./PerpFixedPoint96.sol"; import { TickMath } from "@uniswap/v3-core/contracts/libraries/TickMath.sol"; import { LiquidityAmounts } from "@uniswap/v3-periphery/contracts/libraries/LiquidityAmounts.sol"; import { SignedSafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol"; library Funding { using PerpSafeCast for uint256; using PerpSafeCast for uint128; using SignedSafeMathUpgradeable for int256; // // STRUCT // /// @dev tw: time-weighted /// @param twPremiumX96 overflow inspection (as twPremiumX96 > twPremiumDivBySqrtPriceX96): // max = 2 ^ (255 - 96) = 2 ^ 159 = 7.307508187E47 // assume premium = 10000, time = 10 year = 60 * 60 * 24 * 365 * 10 -> twPremium = 3.1536E12 struct Growth { int256 twPremiumX96; int256 twPremiumDivBySqrtPriceX96; } // // CONSTANT // /// @dev block-based funding is calculated as: premium * timeFraction / 1 day, for 1 day as the default period int256 internal constant _DEFAULT_FUNDING_PERIOD = 1 days; // // INTERNAL PURE // function calcPendingFundingPaymentWithLiquidityCoefficient( int256 baseBalance, int256 twPremiumGrowthGlobalX96, Growth memory fundingGrowthGlobal, int256 liquidityCoefficientInFundingPayment ) internal pure returns (int256) { int256 balanceCoefficientInFundingPayment = PerpMath.mulDiv( baseBalance, fundingGrowthGlobal.twPremiumX96.sub(twPremiumGrowthGlobalX96), uint256(PerpFixedPoint96._IQ96) ); return liquidityCoefficientInFundingPayment.add(balanceCoefficientInFundingPayment).div(_DEFAULT_FUNDING_PERIOD); } /// @dev the funding payment of an order/liquidity is composed of /// 1. funding accrued inside the range 2. funding accrued below the range /// there is no funding when the price goes above the range, as liquidity is all swapped into quoteToken /// @return liquidityCoefficientInFundingPayment the funding payment of an order/liquidity function calcLiquidityCoefficientInFundingPaymentByOrder( OpenOrder.Info memory order, Tick.FundingGrowthRangeInfo memory fundingGrowthRangeInfo ) internal pure returns (int256) { uint160 sqrtPriceX96AtUpperTick = TickMath.getSqrtRatioAtTick(order.upperTick); // base amount below the range uint256 baseAmountBelow = LiquidityAmounts.getAmount0ForLiquidity( TickMath.getSqrtRatioAtTick(order.lowerTick), sqrtPriceX96AtUpperTick, order.liquidity ); // funding below the range int256 fundingBelowX96 = baseAmountBelow.toInt256().mul( fundingGrowthRangeInfo.twPremiumGrowthBelowX96.sub(order.lastTwPremiumGrowthBelowX96) ); // funding inside the range = // liquidity * (ΔtwPremiumDivBySqrtPriceGrowthInsideX96 - ΔtwPremiumGrowthInsideX96 / sqrtPriceAtUpperTick) int256 fundingInsideX96 = order.liquidity.toInt256().mul( // ΔtwPremiumDivBySqrtPriceGrowthInsideX96 fundingGrowthRangeInfo .twPremiumDivBySqrtPriceGrowthInsideX96 .sub(order.lastTwPremiumDivBySqrtPriceGrowthInsideX96) .sub( // ΔtwPremiumGrowthInsideX96 PerpMath.mulDiv( fundingGrowthRangeInfo.twPremiumGrowthInsideX96.sub(order.lastTwPremiumGrowthInsideX96), PerpFixedPoint96._IQ96, sqrtPriceX96AtUpperTick ) ) ); return fundingBelowX96.add(fundingInsideX96).div(PerpFixedPoint96._IQ96); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; library OpenOrder { /// @param lastFeeGrowthInsideX128 fees in quote token recorded in Exchange /// because of block-based funding, quote-only and customized fee, all fees are in quote token struct Info { uint128 liquidity; int24 lowerTick; int24 upperTick; uint256 lastFeeGrowthInsideX128; int256 lastTwPremiumGrowthInsideX96; int256 lastTwPremiumGrowthBelowX96; int256 lastTwPremiumDivBySqrtPriceGrowthInsideX96; uint256 baseDebt; uint256 quoteDebt; } function calcOrderKey( address trader, address baseToken, int24 lowerTick, int24 upperTick ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(trader, baseToken, lowerTick, upperTick)); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; library PerpFixedPoint96 { int256 internal constant _IQ96 = 0x1000000000000000000000000; }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; pragma abicoder v2; import { FixedPoint96 } from "@uniswap/v3-core/contracts/libraries/FixedPoint96.sol"; import { FullMath } from "@uniswap/v3-core/contracts/libraries/FullMath.sol"; import { PerpSafeCast } from "./PerpSafeCast.sol"; import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/MathUpgradeable.sol"; import { SafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; import { SignedSafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol"; library PerpMath { using PerpSafeCast for int256; using SignedSafeMathUpgradeable for int256; using SafeMathUpgradeable for uint256; function formatSqrtPriceX96ToPriceX96(uint160 sqrtPriceX96) internal pure returns (uint256) { return FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, FixedPoint96.Q96); } function formatX10_18ToX96(uint256 valueX10_18) internal pure returns (uint256) { return FullMath.mulDiv(valueX10_18, FixedPoint96.Q96, 1 ether); } function formatX96ToX10_18(uint256 valueX96) internal pure returns (uint256) { return FullMath.mulDiv(valueX96, 1 ether, FixedPoint96.Q96); } function max(int256 a, int256 b) internal pure returns (int256) { return a >= b ? a : b; } function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } function abs(int256 value) internal pure returns (uint256) { return value >= 0 ? value.toUint256() : neg256(value).toUint256(); } function neg256(int256 a) internal pure returns (int256) { require(a > -2**255, "PerpMath: inversion overflow"); return -a; } function neg256(uint256 a) internal pure returns (int256) { return -PerpSafeCast.toInt256(a); } function neg128(int128 a) internal pure returns (int128) { require(a > -2**127, "PerpMath: inversion overflow"); return -a; } function neg128(uint128 a) internal pure returns (int128) { return -PerpSafeCast.toInt128(a); } function divBy10_18(int256 value) internal pure returns (int256) { // no overflow here return value / (1 ether); } function divBy10_18(uint256 value) internal pure returns (uint256) { // no overflow here return value / (1 ether); } function subRatio(uint24 a, uint24 b) internal pure returns (uint24) { require(b <= a, "PerpMath: subtraction overflow"); return a - b; } function mulRatio(uint256 value, uint24 ratio) internal pure returns (uint256) { return FullMath.mulDiv(value, ratio, 1e6); } function mulRatio(int256 value, uint24 ratio) internal pure returns (int256) { return mulDiv(value, int256(ratio), 1e6); } function divRatio(uint256 value, uint24 ratio) internal pure returns (uint256) { return FullMath.mulDiv(value, 1e6, ratio); } /// @param denominator cannot be 0 and is checked in FullMath.mulDiv() function mulDiv( int256 a, int256 b, uint256 denominator ) internal pure returns (int256 result) { uint256 unsignedA = a < 0 ? uint256(neg256(a)) : uint256(a); uint256 unsignedB = b < 0 ? uint256(neg256(b)) : uint256(b); bool negative = ((a < 0 && b > 0) || (a > 0 && b < 0)) ? true : false; uint256 unsignedResult = FullMath.mulDiv(unsignedA, unsignedB, denominator); result = negative ? neg256(unsignedResult) : PerpSafeCast.toInt256(unsignedResult); return result; } function findMedianOfThree( uint256 v1, uint256 v2, uint256 v3 ) internal pure returns (uint256) { return MathUpgradeable.max(MathUpgradeable.min(v1, v2), MathUpgradeable.min(MathUpgradeable.max(v1, v2), v3)); } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.6; /** * @dev copy from "@openzeppelin/contracts-upgradeable/utils/SafeCastUpgradeable.sol" * and rename to avoid naming conflict with uniswap */ library PerpSafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128 returnValue) { require(((returnValue = uint128(value)) == value), "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64 returnValue) { require(((returnValue = uint64(value)) == value), "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32 returnValue) { require(((returnValue = uint32(value)) == value), "SafeCast: value doesn't fit in 32 bits"); } /** * @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 */ function toUint24(uint256 value) internal pure returns (uint24 returnValue) { require(((returnValue = uint24(value)) == value), "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16 returnValue) { require(((returnValue = uint16(value)) == value), "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits. */ function toUint8(uint256 value) internal pure returns (uint8 returnValue) { require(((returnValue = uint8(value)) == value), "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 returnValue) { require(((returnValue = int128(value)) == value), "SafeCast: value doesn't fit in 128 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 returnValue) { require(((returnValue = int64(value)) == value), "SafeCast: value doesn't fit in 64 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 returnValue) { require(((returnValue = int32(value)) == value), "SafeCast: value doesn't fit in 32 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 returnValue) { require(((returnValue = int16(value)) == 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 returnValue) { require(((returnValue = int8(value)) == 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. */ function toInt256(uint256 value) internal pure returns (int256) { require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } /** * @dev Returns the downcasted uint24 from int256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must be greater than or equal to 0 and into 24 bit. */ function toUint24(int256 value) internal pure returns (uint24 returnValue) { require( ((returnValue = uint24(value)) == value), "SafeCast: value must be positive or value doesn't fit in an 24 bits" ); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 returnValue) { require(((returnValue = int24(value)) == value), "SafeCast: value doesn't fit in an 24 bits"); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; library Tick { struct GrowthInfo { uint256 feeX128; int256 twPremiumX96; int256 twPremiumDivBySqrtPriceX96; } struct FundingGrowthRangeInfo { int256 twPremiumGrowthInsideX96; int256 twPremiumGrowthBelowX96; int256 twPremiumDivBySqrtPriceGrowthInsideX96; } /// @dev call this function only if (liquidityGrossBefore == 0 && liquidityDelta != 0) /// @dev per Uniswap: we assume that all growths before a tick is initialized happen "below" the tick function initialize( mapping(int24 => GrowthInfo) storage self, int24 tick, int24 currentTick, GrowthInfo memory globalGrowthInfo ) internal { if (tick <= currentTick) { GrowthInfo storage growthInfo = self[tick]; growthInfo.feeX128 = globalGrowthInfo.feeX128; growthInfo.twPremiumX96 = globalGrowthInfo.twPremiumX96; growthInfo.twPremiumDivBySqrtPriceX96 = globalGrowthInfo.twPremiumDivBySqrtPriceX96; } } function cross( mapping(int24 => GrowthInfo) storage self, int24 tick, GrowthInfo memory globalGrowthInfo ) internal { GrowthInfo storage growthInfo = self[tick]; growthInfo.feeX128 = globalGrowthInfo.feeX128 - growthInfo.feeX128; growthInfo.twPremiumX96 = globalGrowthInfo.twPremiumX96 - growthInfo.twPremiumX96; growthInfo.twPremiumDivBySqrtPriceX96 = globalGrowthInfo.twPremiumDivBySqrtPriceX96 - growthInfo.twPremiumDivBySqrtPriceX96; } function clear(mapping(int24 => GrowthInfo) storage self, int24 tick) internal { delete self[tick]; } /// @dev all values in this function are scaled by 2^128 (X128), thus adding the suffix to external params /// @return feeGrowthInsideX128 this value can underflow per Tick.feeGrowthOutside specs function getFeeGrowthInsideX128( mapping(int24 => GrowthInfo) storage self, int24 lowerTick, int24 upperTick, int24 currentTick, uint256 feeGrowthGlobalX128 ) internal view returns (uint256 feeGrowthInsideX128) { uint256 lowerFeeGrowthOutside = self[lowerTick].feeX128; uint256 upperFeeGrowthOutside = self[upperTick].feeX128; uint256 feeGrowthBelow = currentTick >= lowerTick ? lowerFeeGrowthOutside : feeGrowthGlobalX128 - lowerFeeGrowthOutside; uint256 feeGrowthAbove = currentTick < upperTick ? upperFeeGrowthOutside : feeGrowthGlobalX128 - upperFeeGrowthOutside; return feeGrowthGlobalX128 - feeGrowthBelow - feeGrowthAbove; } /// @return all values returned can underflow per feeGrowthOutside specs; /// see https://www.notion.so/32990980ba8b43859f6d2541722a739b function getAllFundingGrowth( mapping(int24 => GrowthInfo) storage self, int24 lowerTick, int24 upperTick, int24 currentTick, int256 twPremiumGrowthGlobalX96, int256 twPremiumDivBySqrtPriceGrowthGlobalX96 ) internal view returns (FundingGrowthRangeInfo memory) { GrowthInfo storage lowerTickGrowthInfo = self[lowerTick]; GrowthInfo storage upperTickGrowthInfo = self[upperTick]; int256 lowerTwPremiumGrowthOutsideX96 = lowerTickGrowthInfo.twPremiumX96; int256 upperTwPremiumGrowthOutsideX96 = upperTickGrowthInfo.twPremiumX96; FundingGrowthRangeInfo memory fundingGrowthRangeInfo; fundingGrowthRangeInfo.twPremiumGrowthBelowX96 = currentTick >= lowerTick ? lowerTwPremiumGrowthOutsideX96 : twPremiumGrowthGlobalX96 - lowerTwPremiumGrowthOutsideX96; int256 twPremiumGrowthAboveX96 = currentTick < upperTick ? upperTwPremiumGrowthOutsideX96 : twPremiumGrowthGlobalX96 - upperTwPremiumGrowthOutsideX96; int256 lowerTwPremiumDivBySqrtPriceGrowthOutsideX96 = lowerTickGrowthInfo.twPremiumDivBySqrtPriceX96; int256 upperTwPremiumDivBySqrtPriceGrowthOutsideX96 = upperTickGrowthInfo.twPremiumDivBySqrtPriceX96; int256 twPremiumDivBySqrtPriceGrowthBelowX96 = currentTick >= lowerTick ? lowerTwPremiumDivBySqrtPriceGrowthOutsideX96 : twPremiumDivBySqrtPriceGrowthGlobalX96 - lowerTwPremiumDivBySqrtPriceGrowthOutsideX96; int256 twPremiumDivBySqrtPriceGrowthAboveX96 = currentTick < upperTick ? upperTwPremiumDivBySqrtPriceGrowthOutsideX96 : twPremiumDivBySqrtPriceGrowthGlobalX96 - upperTwPremiumDivBySqrtPriceGrowthOutsideX96; fundingGrowthRangeInfo.twPremiumGrowthInsideX96 = twPremiumGrowthGlobalX96 - fundingGrowthRangeInfo.twPremiumGrowthBelowX96 - twPremiumGrowthAboveX96; fundingGrowthRangeInfo.twPremiumDivBySqrtPriceGrowthInsideX96 = twPremiumDivBySqrtPriceGrowthGlobalX96 - twPremiumDivBySqrtPriceGrowthBelowX96 - twPremiumDivBySqrtPriceGrowthAboveX96; return fundingGrowthRangeInfo; } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity 0.7.6; import { AccountMarket } from "../lib/AccountMarket.sol"; /// @notice For future upgrades, do not change AccountBalanceStorageV1. Create a new /// contract which implements AccountBalanceStorageV1 and following the naming convention /// AccountBalanceStorageVX. abstract contract AccountBalanceStorageV1 { address internal _clearingHouseConfig; address internal _orderBook; address internal _vault; // trader => owedRealizedPnl mapping(address => int256) internal _owedRealizedPnlMap; // trader => baseTokens // base token registry of each trader mapping(address => address[]) internal _baseTokensMap; // first key: trader, second key: baseToken mapping(address => mapping(address => AccountMarket.Info)) internal _accountMarketMap; }
{ "evmVersion": "berlin", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 100 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clearingHouse","type":"address"}],"name":"ClearingHouseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"}],"name":"PnlRealized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"VaultChanged","type":"event"},{"inputs":[],"name":"candidate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"deregisterBaseToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getAccountInfo","outputs":[{"components":[{"internalType":"int256","name":"takerPositionSize","type":"int256"},{"internalType":"int256","name":"takerOpenNotional","type":"int256"},{"internalType":"int256","name":"lastTwPremiumGrowthGlobalX96","type":"int256"}],"internalType":"struct AccountMarket.Info","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getBase","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getBaseTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClearingHouse","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClearingHouseConfig","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"int256","name":"accountValue","type":"int256"}],"name":"getLiquidatablePositionSize","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getMarginRequirementForLiquidation","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"}],"name":"getMarkPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOrderBook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getPnlAndPendingFee","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getQuote","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getTakerOpenNotional","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getTakerPositionSize","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getTotalAbsPositionValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getTotalDebtValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getTotalOpenNotional","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getTotalPositionSize","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"getTotalPositionValue","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"hasOrder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"clearingHouseConfigArg","type":"address"},{"internalType":"address","name":"orderBookArg","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"int256","name":"amount","type":"int256"}],"name":"modifyOwedRealizedPnl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"int256","name":"base","type":"int256"},{"internalType":"int256","name":"quote","type":"int256"}],"name":"modifyTakerBalance","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"registerBaseToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"clearingHouseArg","type":"address"}],"name":"setClearingHouse","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vaultArg","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"int256","name":"takerBase","type":"int256"},{"internalType":"int256","name":"takerQuote","type":"int256"},{"internalType":"int256","name":"realizedPnl","type":"int256"},{"internalType":"int256","name":"makerFee","type":"int256"}],"name":"settleBalanceAndDeregister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"settleOwedRealizedPnl","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"}],"name":"settlePositionInClosedMarket","outputs":[{"internalType":"int256","name":"positionNotional","type":"int256"},{"internalType":"int256","name":"openNotional","type":"int256"},{"internalType":"int256","name":"realizedPnl","type":"int256"},{"internalType":"uint256","name":"closedPrice","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"int256","name":"amount","type":"int256"}],"name":"settleQuoteToOwedRealizedPnl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"int256","name":"lastTwPremiumGrowthGlobalX96","type":"int256"}],"name":"updateTwPremiumGrowthGlobal","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b5061333e806100206000396000f3fe608060405234801561001057600080fd5b50600436106101f75760003560e01c806389f9217711610120578063bba85bcf116100b8578063ec647a121161007c578063ec647a121461047d578063f75c266d14610490578063fa8e30af146104a3578063fc737214146104b6578063fd6ceee5146104c9576101f7565b8063bba85bcf14610418578063bc5920ba1461043a578063c575ff7914610442578063cb3c7b8e1461044a578063d50d01b71461046a576101f7565b806389f921771461038c5780638d928af81461039f5780638da5cb5b146103a7578063aa2a8294146103af578063af74e736146103b7578063b248c4ef146103d7578063b2e27148146103df578063b3945690146103f2578063b3bd6e1214610405576101f7565b80635f9d05ad116101935780635f9d05ad146102cd5780636332fef6146102f05780636817031b1461031057806368f12e12146103235780636c8381f8146103365780636ccdc82e1461034b578063715018a61461035e5780637a5b45a014610366578063874044f314610379576101f7565b806310485bec146101fc57806313af403514610225578063293a50771461023a5780632e4586c31461024d5780633c9b5ad1146102605780633f93510714610281578063449323d814610294578063485cc955146102a75780635d6f9c14146102ba575b600080fd5b61020f61020a366004612c83565b6104dc565b60405161021c919061305c565b60405180910390f35b610238610233366004612c13565b6105b2565b005b61020f610248366004612c13565b61070d565b61023861025b366004612c83565b61080b565b61027361026e366004612cc3565b610842565b60405161021c929190613065565b61020f61028f366004612c4b565b610866565b6102386102a2366004612c13565b610889565b6102386102b5366004612c4b565b610930565b61020f6102c8366004612c13565b610a71565b6102e06102db366004612c4b565b610a7c565b60405161021c9493929190613073565b6103036102fe366004612c4b565b610b7f565b60405161021c919061319e565b61023861031e366004612c13565b610bd6565b61020f610331366004612c4b565b610cab565b61033e610e3b565b60405161021c9190612f4d565b61020f610359366004612c13565b610e4a565b610238610f13565b61020f610374366004612c4b565b610fb4565b610238610387366004612d60565b61107a565b61023861039a366004612d08565b611090565b61033e6110cd565b61033e6110dc565b61033e6110eb565b6103ca6103c5366004612c13565b6110fa565b60405161021c919061303e565b61033e611170565b61020f6103ed366004612c4b565b61117f565b61020f610400366004612c4b565b6111c7565b61020f610413366004612c4b565b61127c565b61042b610426366004612c13565b611340565b60405161021c9392919061308e565b61023861140a565b61033e6114f6565b61045d610458366004612c13565b611505565b60405161021c9190613051565b61020f610478366004612c4b565b6116e3565b61023861048b366004612c83565b611711565b61020f61049e366004612c13565b611724565b6102386104b1366004612c4b565b6117c1565b6102386104c4366004612c4b565b6117d3565b61020f6104d7366004612c13565b61192c565b6000806104e885611724565b905060006104f68686610cab565b90508184121580610505575080155b15610515576000925050506105ab565b60006105296105248784611989565b6119c1565b905068056bc75e2d631000008111610545575091506105ab9050565b620f42406105548460026119ea565b861261059a5761058261057d6105698a610e4a565b620f4240610578866002611aa2565b611afb565b611baa565b9050620f42408162ffffff16111561059a5750620f42405b6105a48382611bee565b9450505050505b9392505050565b6105ba611c03565b6001600160a01b03166105cb6110dc565b6001600160a01b03161461060f576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b6001600160a01b038116610653576040805162461bcd60e51b81526020600482015260066024820152650534f5f4e57360d41b604482015290519081900360640190fd5b6033546001600160a01b038281169116141561069f576040805162461bcd60e51b8152602060048201526006602482015265534f5f53414f60d01b604482015290519081900360640190fd5b6034546001600160a01b03828116911614156106eb576040805162461bcd60e51b8152602060048201526006602482015265534f5f53414360d01b604482015290519081900360640190fd5b603480546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166000908152609e602052604081205481908190815b818110156107dc576001600160a01b0386166000908152609e6020526040812080548390811061075857fe5b60009182526020822001546001600160a01b03169150610778888361127c565b90506000808212156107ab576107a861079861079385611c07565b611de6565b8390670de0b6b3a7640000611e32565b90505b6107b58682611eca565b95506107cb6107c48a85610fb4565b8890611eca565b9650506001909201915061072c9050565b506000808412156107ed57836107f0565b60005b90506107ff6105248285611eca565b9450505050505b919050565b610813611f2f565b6001600160a01b039283166000908152609f602090815260408083209490951682529290925291902060020155565b60008061084d611f2f565b61085986868686611f6b565b9150915094509492505050565b6000806108738484610cab565b905061087f8382611989565b9150505b92915050565b610891611c03565b6001600160a01b03166108a26110dc565b6001600160a01b0316146108e6576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b606780546001600160a01b0319166001600160a01b0383169081179091556040517fd0654f5900f9e7e4e605a19334306e6a2786bbf960ac0484a4c12feb6428fe2f90600090a250565b600054610100900460ff16806109495750610949611fc7565b80610957575060005460ff16155b6109925760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff161580156109bd576000805460ff1961ff0019909116610100171660011790555b6109cf836001600160a01b0316611fd8565b6109f45760405162461bcd60e51b81526004016109eb906130a4565b60405180910390fd5b610a06826001600160a01b0316611fd8565b610a225760405162461bcd60e51b81526004016109eb9061313e565b610a2a611fde565b609a80546001600160a01b038086166001600160a01b031992831617909255609b8054928516929091169190911790558015610a6c576000805461ff00191690555b505050565b600061088382612088565b600080600080610a8a611f2f565b6000610a96878761117f565b9050856001600160a01b03166357a48b016040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad157600080fd5b505afa158015610ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b099190612e9f565b9150610b27610b1783611de6565b8290670de0b6b3a7640000611e32565b6001600160a01b038089166000908152609f60209081526040808320938b16835292905220600101549095509350610b5f8585611eca565b9250610b6b878761217a565b610b7587846122ac565b5092959194509250565b610b87612bde565b506001600160a01b039182166000908152609f60209081526040808320939094168252918252829020825160608101845281548152600182015492810192909252600201549181019190915290565b610bde611c03565b6001600160a01b0316610bef6110dc565b6001600160a01b031614610c33576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b610c45816001600160a01b0316611fd8565b610c615760405162461bcd60e51b81526004016109eb9061317e565b609c80546001600160a01b0319166001600160a01b0383169081179091556040517fa49691f0dd6477ccef49962612a236d252e3a31c3be8b61fa6abeff3e74a757290600090a250565b609b54604051635d8a541d60e01b815260009182916001600160a01b0390911690635d8a541d90610ce59087908790600190600401612f7b565b604080518083038186803b158015610cfc57600080fd5b505afa158015610d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d349190612e59565b50609b54604051637c2b7c5360e01b81529192506000916001600160a01b0390911690637c2b7c5390610d709088908890600190600401612f7b565b60206040518083038186803b158015610d8857600080fd5b505afa158015610d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc09190612e9f565b90506000610ddf610dd083611de6565b610dd985611de6565b9061232e565b6001600160a01b038088166000908152609f60209081526040808320938a16835292905290812054919250610e148383611eca565b9050600a610e21826119c1565b10610e2c5780610e2f565b60005b98975050505050505050565b6034546001600160a01b031690565b6001600160a01b0381166000908152609e6020908152604080832080548251818502810185019093528083528493830182828015610eb157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e93575b505050505090506000808251905060005b81811015610f09576000848281518110610ed857fe5b602002602001015190506000610ef16105248984610866565b9050610efd8582612393565b94505050600101610ec2565b5090949350505050565b610f1b611c03565b6001600160a01b0316610f2c6110dc565b6001600160a01b031614610f70576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b6033546040516000916001600160a01b031690600080516020613277833981519152908390a3603380546001600160a01b0319908116909155603480549091169055565b609b54604051637c2b7c5360e01b815260009182916001600160a01b0390911690637c2b7c5390610fed90879087908690600401612f7b565b60206040518083038186803b15801561100557600080fd5b505afa158015611019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103d9190612e9f565b905061087f61104b82611de6565b6001600160a01b038087166000908152609f60209081526040808320938916835292905220600101549061232e565b611082611f2f565b61108c82826122ac565b5050565b611098611f2f565b6110a486868686611f6b565b50506110b086826122ac565b6110bb8686846123ed565b6110c5868661243c565b505050505050565b609c546001600160a01b031690565b6033546001600160a01b031690565b609a546001600160a01b031690565b6001600160a01b0381166000908152609e602090815260409182902080548351818402810184019094528084526060939283018282801561116457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611146575b50505050509050919050565b609b546001600160a01b031690565b6001600160a01b038083166000908152609f60209081526040808320938516835292905290812054600a6111b2826119c1565b106111bd578061087f565b5060009392505050565b609b54604051635d8a541d60e01b815260009182916001600160a01b0390911690635d8a541d9061120090879087908690600401612f7b565b604080518083038186803b15801561121757600080fd5b505afa15801561122b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124f9190612e59565b509050600061125e8585610fb4565b90506112738161126d84611de6565b90611eca565b95945050505050565b609b54604051637c2b7c5360e01b815260009182916001600160a01b0390911690637c2b7c53906112b69087908790600190600401612f7b565b60206040518083038186803b1580156112ce57600080fd5b505afa1580156112e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113069190612e9f565b905061087f61131482611de6565b6001600160a01b038087166000908152609f60209081526040808320938916835292905220549061232e565b6001600160a01b0381166000908152609e6020526040812054819081908190815b818110156113c3576001600160a01b0387166000908152609e6020526040812080548390811061138d57fe5b6000918252602090912001546001600160a01b031690506113b86113b18983610866565b8590611eca565b935050600101611361565b506000806113d088612559565b909250905060006113e18584611eca565b6001600160a01b03999099166000908152609d6020526040902054999197509095505050505050565b6034546001600160a01b031661144f576040805162461bcd60e51b81526020600482015260056024820152640534f5f43360dc1b604482015290519081900360640190fd5b611457611c03565b6034546001600160a01b039081169116146114a2576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4360d01b604482015290519081900360640190fd5b6034546033546040516001600160a01b03928316929091169060008051602061327783398151915290600090a360348054603380546001600160a01b03199081166001600160a01b03841617909155169055565b6067546001600160a01b031690565b6001600160a01b0381166000908152609e6020526040812054818167ffffffffffffffff8111801561153657600080fd5b50604051908082528060200260200182016040528015611560578160200160208202803683370190505b5090506000805b83811015611660576001600160a01b0386166000908152609e6020526040812080548390811061159357fe5b60009182526020918290200154604080516347535d7b60e01b815290516001600160a01b03909216935083926347535d7b92600480840193829003018186803b1580156115df57600080fd5b505afa1580156115f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116179190612e39565b6116275750600190910190611658565b80848484038151811061163657fe5b60200260200101906001600160a01b031690816001600160a01b031681525050505b600101611567565b50609b54604051634dffaee560e01b81526001600160a01b0390911690634dffaee5906116939088908690600401612f9f565b60206040518083038186803b1580156116ab57600080fd5b505afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112739190612e39565b6001600160a01b039182166000908152609f6020908152604080832093909416825291909152206001015490565b611719611f2f565b610a6c8383836123ed565b6000610883610793609a60009054906101000a90046001600160a01b03166001600160a01b031663a85494026040518163ffffffff1660e01b815260040160206040518083038186803b15801561177a57600080fd5b505afa15801561178e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b29190612e7c565b6117bb85610e4a565b9061269d565b6117c9611f2f565b61108c828261243c565b6117db611f2f565b6001600160a01b0382166000908152609e602090815260409182902080548351818402810184019094528084529092611856929091849183018282801561184b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161182d575b5050505050836126b2565b15611861575061108c565b8054600181018255600082815260209081902090910180546001600160a01b0319166001600160a01b0385811691909117909155609a5460408051631623e65d60e11b815290519190921692632c47ccba9260048082019391829003018186803b1580156118ce57600080fd5b505afa1580156118e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119069190612ee9565b60ff1681805490501115610a6c5760405162461bcd60e51b81526004016109eb906130e7565b609c546000906001600160a01b0316611943611c03565b6001600160a01b0316146119695760405162461bcd60e51b81526004016109eb9061315f565b506001600160a01b03166000908152609d60205260408120805491905590565b60008161199857506000610883565b60006119a384611c07565b905061087f6119b182611de6565b8490670de0b6b3a7640000611e32565b6000808212156119e1576119dc6119d7836126fe565b61272a565b610883565b6108838261272a565b600081611a3e576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b81600019148015611a525750600160ff1b83145b15611a8e5760405162461bcd60e51b81526004018080602001828103825260218152602001806132356021913960400191505060405180910390fd5b6000828481611a9957fe5b05949350505050565b600082611ab157506000610883565b82820282848281611abe57fe5b04146105ab5760405162461bcd60e51b81526004018080602001828103825260218152602001806132566021913960400191505060405180910390fd5b6000808060001985870986860292508281109083900303905080611b315760008411611b2657600080fd5b5082900490506105ab565b808411611b3d57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b8062ffffff811681146108065760405162461bcd60e51b81526004018080602001828103825260268152602001806132e36026913960400191505060405180910390fd5b60006105ab838362ffffff16620f4240611e32565b3390565b6000816001600160a01b03166347535d7b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c4257600080fd5b505afa158015611c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7a9190612e39565b15611c8f57611c8882612088565b9050610806565b816001600160a01b031663c2b6b58c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cc857600080fd5b505afa158015611cdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d009190612e39565b611d7557816001600160a01b0316631c2ab4056040518163ffffffff1660e01b815260040160206040518083038186803b158015611d3d57600080fd5b505afa158015611d51573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc9190612e9f565b816001600160a01b03166357a48b016040518163ffffffff1660e01b815260040160206040518083038186803b158015611dae57600080fd5b505afa158015611dc2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108839190612e9f565b60006001600160ff1b03821115611e2e5760405162461bcd60e51b81526004018080602001828103825260288152602001806132976028913960400191505060405180910390fd5b5090565b60008060008512611e435784611e4c565b611e4c856126fe565b90506000808512611e5d5784611e66565b611e66856126fe565b905060008087128015611e795750600086135b80611e8f5750600087138015611e8f5750600086125b611e9a576000611e9d565b60015b90506000611eac848488611afb565b905081611ec157611ebc81611de6565b6105a4565b6105a481612781565b6000828201818312801590611edf5750838112155b80611ef45750600083128015611ef457508381125b6105ab5760405162461bcd60e51b81526004018080602001828103825260218152602001806131e66021913960400191505060405180910390fd5b6067546001600160a01b0316611f43611c03565b6001600160a01b031614611f695760405162461bcd60e51b81526004016109eb906130c6565b565b6001600160a01b038085166000908152609f6020908152604080832093871683529290529081208054829190611fa19086611eca565b81556001810154611fb29085611eca565b60018201819055905497909650945050505050565b6000611fd230611fd8565b15905090565b3b151590565b600054610100900460ff1680611ff75750611ff7611fc7565b80612005575060005460ff16155b6120405760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff1615801561206b576000805460ff1961ff0019909116610100171660011790555b612073612795565b8015612085576000805461ff00191690555b50565b609a546040805163b0a336a760e01b815281516000936001600160a01b03169284928392859263b0a336a79260048082019391829003018186803b1580156120cf57600080fd5b505afa1580156120e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121079190612eb7565b915091506000612118866000612884565b905060006121268785612884565b9050600061214761213a6107938a876129a2565b610dd96107938b88612884565b905060006121606119d78361126d6107938d60006129a2565b905061216d848483612a21565b9998505050505050505050565b6001600160a01b038083166000818152609f60209081526040808320948616835293815283822082815560018101839055600201829055918152609e909152908120805490915b818110156122a557836001600160a01b03168382815481106121df57fe5b6000918252602090912001546001600160a01b0316141561229d5760018203811461226c5782600183038154811061221357fe5b9060005260206000200160009054906101000a90046001600160a01b031683828154811061223d57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b8280548061227657fe5b600082815260209020810160001990810180546001600160a01b03191690550190556122a5565b6001016121c1565b5050505050565b801561108c576001600160a01b0382166000908152609d60205260409020546122d59082611eca565b6001600160a01b0383166000818152609d6020526040908190209290925590517febf4e69d81451d269fc4d9551b06d58bea2ed426d2c528919ce45f6070946efb9061232290849061305c565b60405180910390a25050565b60008183038183128015906123435750838113155b80612358575060008312801561235857508381135b6105ab5760405162461bcd60e51b81526004018080602001828103825260248152602001806132bf6024913960400191505060405180910390fd5b6000828201838110156105ab576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b8015610a6c576001600160a01b038084166000908152609f602090815260408083209386168352929052206001810154612427908361232e565b600182015561243684836122ac565b50505050565b6001600160a01b038083166000908152609f602090815260408083209385168352928152908290208251606081018452815480825260018301549382019390935260029091015492810192909252600a90612496906119c1565b1015806124b05750600a6124ad82602001516119c1565b10155b156124bb575061108c565b609b546040516321b499f560e11b81526000916001600160a01b03169063436933ea906124ee9087908790600401612f61565b60006040518083038186803b15801561250657600080fd5b505afa15801561251a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125429190810190612d8b565b51111561254f575061108c565b610a6c838361217a565b6001600160a01b0381166000908152609e602052604081205481908190815b818110156125f1576001600160a01b0386166000908152609e602052604081208054839081106125a457fe5b60009182526020808320909101546001600160a01b038a81168452609f83526040808520919092168085529252909120600101549091506125e6908590611eca565b935050600101612578565b50609b546001600160a01b038681166000908152609e6020526040808220905163d0581a9360e01b81529193929092169163d0581a9391612636918a91600401612fc3565b604080518083038186803b15801561264d57600080fd5b505afa158015612661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126859190612e59565b945090506126938382611eca565b9450505050915091565b60006105ab838362ffffff16620f4240611afb565b6000805b83518110156111bd57826001600160a01b03168482815181106126d557fe5b60200260200101516001600160a01b031614156126f6576001915050610883565b6001016126b6565b6000600160ff1b82136127235760405162461bcd60e51b81526004016109eb90613107565b5060000390565b600080821215611e2e576040805162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015290519081900360640190fd5b600061278c82611de6565b60000392915050565b600054610100900460ff16806127ae57506127ae611fc7565b806127bc575060005460ff16155b6127f75760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff16158015612822576000805460ff1961ff0019909116610100171660011790555b61282a612a50565b6000612834611c03565b603380546001600160a01b0319166001600160a01b03831690811790915560405191925090600090600080516020613277833981519152908290a3508015612085576000805461ff001916905550565b60006105ab61299d609b60009054906101000a90046001600160a01b03166001600160a01b031663f807cd226040518163ffffffff1660e01b815260040160206040518083038186803b1580156128da57600080fd5b505afa1580156128ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129129190612c2f565b6001600160a01b031663dc7e7e1686866040518363ffffffff1660e01b815260040161293f92919061301f565b60206040518083038186803b15801561295757600080fd5b505afa15801561296b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298f9190612c2f565b6001600160a01b0316612ae5565b612aff565b604051631208064760e01b81526000906001600160a01b038416906312080647906129d19085906004016131bf565b60206040518083038186803b1580156129e957600080fd5b505afa1580156129fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ab9190612e9f565b6000612a48612a308585612b18565b612a43612a3d8787612b2e565b85612b18565b612b2e565b949350505050565b600054610100900460ff1680612a695750612a69611fc7565b80612a77575060005460ff16155b612ab25760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff16158015612add576000805460ff1961ff0019909116610100171660011790555b612073612b3e565b60006108836001600160a01b03831680600160601b611afb565b600061088382670de0b6b3a7640000600160601b611afb565b6000818310612b2757816105ab565b5090919050565b600081831015612b2757816105ab565b600054610100900460ff1680612b575750612b57611fc7565b80612b65575060005460ff16155b612ba05760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff16158015612073576000805460ff1961ff0019909116610100171660011790558015612085576000805461ff001916905550565b60405180606001604052806000815260200160008152602001600081525090565b805163ffffffff8116811461080657600080fd5b600060208284031215612c24578081fd5b81356105ab816131d0565b600060208284031215612c40578081fd5b81516105ab816131d0565b60008060408385031215612c5d578081fd5b8235612c68816131d0565b91506020830135612c78816131d0565b809150509250929050565b600080600060608486031215612c97578081fd5b8335612ca2816131d0565b92506020840135612cb2816131d0565b929592945050506040919091013590565b60008060008060808587031215612cd8578081fd5b8435612ce3816131d0565b93506020850135612cf3816131d0565b93969395505050506040820135916060013590565b60008060008060008060c08789031215612d20578182fd5b8635612d2b816131d0565b95506020870135612d3b816131d0565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60008060408385031215612d72578182fd5b8235612d7d816131d0565b946020939093013593505050565b60006020808385031215612d9d578182fd5b825167ffffffffffffffff80821115612db4578384fd5b818501915085601f830112612dc7578384fd5b815181811115612dd357fe5b83810260405185828201018181108582111715612dec57fe5b604052828152858101935084860182860187018a1015612e0a578788fd5b8795505b83861015612e2c578051855260019590950194938601938601612e0e565b5098975050505050505050565b600060208284031215612e4a578081fd5b815180151581146105ab578182fd5b60008060408385031215612e6b578182fd5b505080516020909101519092909150565b600060208284031215612e8d578081fd5b815162ffffff811681146105ab578182fd5b600060208284031215612eb0578081fd5b5051919050565b60008060408385031215612ec9578182fd5b612ed283612bff565b9150612ee060208401612bff565b90509250929050565b600060208284031215612efa578081fd5b815160ff811681146105ab578182fd5b6000815180845260208085019450808401835b83811015612f425781516001600160a01b031687529582019590820190600101612f1d565b509495945050505050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152901515604082015260600190565b6001600160a01b0383168152604060208201819052600090612a4890830184612f0a565b60006040820160018060a01b03808616845260206040818601528286548085526060870191508786528286209450855b81811015613011578554851683526001958601959284019201612ff3565b509098975050505050505050565b6001600160a01b0392909216825263ffffffff16602082015260400190565b6000602082526105ab6020830184612f0a565b901515815260200190565b90815260200190565b918252602082015260400190565b93845260208401929092526040830152606082015260800190565b9283526020830191909152604082015260600190565b60208082526008908201526741425f4348434e4360c01b604082015260600190565b6020808252600790820152660869088be9e86960cb1b604082015260600190565b60208082526006908201526541425f4d4e4560d01b604082015260600190565b6020808252601c908201527f506572704d6174683a20696e76657273696f6e206f766572666c6f7700000000604082015260600190565b60208082526007908201526641425f4f424e4360c81b604082015260600190565b60208082526005908201526420a12fa7ab60d91b604082015260600190565b60208082526006908201526541425f564e4360d01b604082015260600190565b81518152602080830151908201526040918201519181019190915260600190565b63ffffffff91909116815260200190565b6001600160a01b038116811461208557600080fdfe5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65645369676e6564536166654d6174683a206469766973696f6e206f766572666c6f77536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f778be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e053616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e743235365369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e2032342062697473a2646970667358221220b010e2662ad64fe701c27bb65d03befe32d9abc4855914cd66e6b619bcb9416f64736f6c63430007060033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101f75760003560e01c806389f9217711610120578063bba85bcf116100b8578063ec647a121161007c578063ec647a121461047d578063f75c266d14610490578063fa8e30af146104a3578063fc737214146104b6578063fd6ceee5146104c9576101f7565b8063bba85bcf14610418578063bc5920ba1461043a578063c575ff7914610442578063cb3c7b8e1461044a578063d50d01b71461046a576101f7565b806389f921771461038c5780638d928af81461039f5780638da5cb5b146103a7578063aa2a8294146103af578063af74e736146103b7578063b248c4ef146103d7578063b2e27148146103df578063b3945690146103f2578063b3bd6e1214610405576101f7565b80635f9d05ad116101935780635f9d05ad146102cd5780636332fef6146102f05780636817031b1461031057806368f12e12146103235780636c8381f8146103365780636ccdc82e1461034b578063715018a61461035e5780637a5b45a014610366578063874044f314610379576101f7565b806310485bec146101fc57806313af403514610225578063293a50771461023a5780632e4586c31461024d5780633c9b5ad1146102605780633f93510714610281578063449323d814610294578063485cc955146102a75780635d6f9c14146102ba575b600080fd5b61020f61020a366004612c83565b6104dc565b60405161021c919061305c565b60405180910390f35b610238610233366004612c13565b6105b2565b005b61020f610248366004612c13565b61070d565b61023861025b366004612c83565b61080b565b61027361026e366004612cc3565b610842565b60405161021c929190613065565b61020f61028f366004612c4b565b610866565b6102386102a2366004612c13565b610889565b6102386102b5366004612c4b565b610930565b61020f6102c8366004612c13565b610a71565b6102e06102db366004612c4b565b610a7c565b60405161021c9493929190613073565b6103036102fe366004612c4b565b610b7f565b60405161021c919061319e565b61023861031e366004612c13565b610bd6565b61020f610331366004612c4b565b610cab565b61033e610e3b565b60405161021c9190612f4d565b61020f610359366004612c13565b610e4a565b610238610f13565b61020f610374366004612c4b565b610fb4565b610238610387366004612d60565b61107a565b61023861039a366004612d08565b611090565b61033e6110cd565b61033e6110dc565b61033e6110eb565b6103ca6103c5366004612c13565b6110fa565b60405161021c919061303e565b61033e611170565b61020f6103ed366004612c4b565b61117f565b61020f610400366004612c4b565b6111c7565b61020f610413366004612c4b565b61127c565b61042b610426366004612c13565b611340565b60405161021c9392919061308e565b61023861140a565b61033e6114f6565b61045d610458366004612c13565b611505565b60405161021c9190613051565b61020f610478366004612c4b565b6116e3565b61023861048b366004612c83565b611711565b61020f61049e366004612c13565b611724565b6102386104b1366004612c4b565b6117c1565b6102386104c4366004612c4b565b6117d3565b61020f6104d7366004612c13565b61192c565b6000806104e885611724565b905060006104f68686610cab565b90508184121580610505575080155b15610515576000925050506105ab565b60006105296105248784611989565b6119c1565b905068056bc75e2d631000008111610545575091506105ab9050565b620f42406105548460026119ea565b861261059a5761058261057d6105698a610e4a565b620f4240610578866002611aa2565b611afb565b611baa565b9050620f42408162ffffff16111561059a5750620f42405b6105a48382611bee565b9450505050505b9392505050565b6105ba611c03565b6001600160a01b03166105cb6110dc565b6001600160a01b03161461060f576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b6001600160a01b038116610653576040805162461bcd60e51b81526020600482015260066024820152650534f5f4e57360d41b604482015290519081900360640190fd5b6033546001600160a01b038281169116141561069f576040805162461bcd60e51b8152602060048201526006602482015265534f5f53414f60d01b604482015290519081900360640190fd5b6034546001600160a01b03828116911614156106eb576040805162461bcd60e51b8152602060048201526006602482015265534f5f53414360d01b604482015290519081900360640190fd5b603480546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b0381166000908152609e602052604081205481908190815b818110156107dc576001600160a01b0386166000908152609e6020526040812080548390811061075857fe5b60009182526020822001546001600160a01b03169150610778888361127c565b90506000808212156107ab576107a861079861079385611c07565b611de6565b8390670de0b6b3a7640000611e32565b90505b6107b58682611eca565b95506107cb6107c48a85610fb4565b8890611eca565b9650506001909201915061072c9050565b506000808412156107ed57836107f0565b60005b90506107ff6105248285611eca565b9450505050505b919050565b610813611f2f565b6001600160a01b039283166000908152609f602090815260408083209490951682529290925291902060020155565b60008061084d611f2f565b61085986868686611f6b565b9150915094509492505050565b6000806108738484610cab565b905061087f8382611989565b9150505b92915050565b610891611c03565b6001600160a01b03166108a26110dc565b6001600160a01b0316146108e6576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b606780546001600160a01b0319166001600160a01b0383169081179091556040517fd0654f5900f9e7e4e605a19334306e6a2786bbf960ac0484a4c12feb6428fe2f90600090a250565b600054610100900460ff16806109495750610949611fc7565b80610957575060005460ff16155b6109925760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff161580156109bd576000805460ff1961ff0019909116610100171660011790555b6109cf836001600160a01b0316611fd8565b6109f45760405162461bcd60e51b81526004016109eb906130a4565b60405180910390fd5b610a06826001600160a01b0316611fd8565b610a225760405162461bcd60e51b81526004016109eb9061313e565b610a2a611fde565b609a80546001600160a01b038086166001600160a01b031992831617909255609b8054928516929091169190911790558015610a6c576000805461ff00191690555b505050565b600061088382612088565b600080600080610a8a611f2f565b6000610a96878761117f565b9050856001600160a01b03166357a48b016040518163ffffffff1660e01b815260040160206040518083038186803b158015610ad157600080fd5b505afa158015610ae5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b099190612e9f565b9150610b27610b1783611de6565b8290670de0b6b3a7640000611e32565b6001600160a01b038089166000908152609f60209081526040808320938b16835292905220600101549095509350610b5f8585611eca565b9250610b6b878761217a565b610b7587846122ac565b5092959194509250565b610b87612bde565b506001600160a01b039182166000908152609f60209081526040808320939094168252918252829020825160608101845281548152600182015492810192909252600201549181019190915290565b610bde611c03565b6001600160a01b0316610bef6110dc565b6001600160a01b031614610c33576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b610c45816001600160a01b0316611fd8565b610c615760405162461bcd60e51b81526004016109eb9061317e565b609c80546001600160a01b0319166001600160a01b0383169081179091556040517fa49691f0dd6477ccef49962612a236d252e3a31c3be8b61fa6abeff3e74a757290600090a250565b609b54604051635d8a541d60e01b815260009182916001600160a01b0390911690635d8a541d90610ce59087908790600190600401612f7b565b604080518083038186803b158015610cfc57600080fd5b505afa158015610d10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d349190612e59565b50609b54604051637c2b7c5360e01b81529192506000916001600160a01b0390911690637c2b7c5390610d709088908890600190600401612f7b565b60206040518083038186803b158015610d8857600080fd5b505afa158015610d9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dc09190612e9f565b90506000610ddf610dd083611de6565b610dd985611de6565b9061232e565b6001600160a01b038088166000908152609f60209081526040808320938a16835292905290812054919250610e148383611eca565b9050600a610e21826119c1565b10610e2c5780610e2f565b60005b98975050505050505050565b6034546001600160a01b031690565b6001600160a01b0381166000908152609e6020908152604080832080548251818502810185019093528083528493830182828015610eb157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e93575b505050505090506000808251905060005b81811015610f09576000848281518110610ed857fe5b602002602001015190506000610ef16105248984610866565b9050610efd8582612393565b94505050600101610ec2565b5090949350505050565b610f1b611c03565b6001600160a01b0316610f2c6110dc565b6001600160a01b031614610f70576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4f60d01b604482015290519081900360640190fd5b6033546040516000916001600160a01b031690600080516020613277833981519152908390a3603380546001600160a01b0319908116909155603480549091169055565b609b54604051637c2b7c5360e01b815260009182916001600160a01b0390911690637c2b7c5390610fed90879087908690600401612f7b565b60206040518083038186803b15801561100557600080fd5b505afa158015611019573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061103d9190612e9f565b905061087f61104b82611de6565b6001600160a01b038087166000908152609f60209081526040808320938916835292905220600101549061232e565b611082611f2f565b61108c82826122ac565b5050565b611098611f2f565b6110a486868686611f6b565b50506110b086826122ac565b6110bb8686846123ed565b6110c5868661243c565b505050505050565b609c546001600160a01b031690565b6033546001600160a01b031690565b609a546001600160a01b031690565b6001600160a01b0381166000908152609e602090815260409182902080548351818402810184019094528084526060939283018282801561116457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611146575b50505050509050919050565b609b546001600160a01b031690565b6001600160a01b038083166000908152609f60209081526040808320938516835292905290812054600a6111b2826119c1565b106111bd578061087f565b5060009392505050565b609b54604051635d8a541d60e01b815260009182916001600160a01b0390911690635d8a541d9061120090879087908690600401612f7b565b604080518083038186803b15801561121757600080fd5b505afa15801561122b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124f9190612e59565b509050600061125e8585610fb4565b90506112738161126d84611de6565b90611eca565b95945050505050565b609b54604051637c2b7c5360e01b815260009182916001600160a01b0390911690637c2b7c53906112b69087908790600190600401612f7b565b60206040518083038186803b1580156112ce57600080fd5b505afa1580156112e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113069190612e9f565b905061087f61131482611de6565b6001600160a01b038087166000908152609f60209081526040808320938916835292905220549061232e565b6001600160a01b0381166000908152609e6020526040812054819081908190815b818110156113c3576001600160a01b0387166000908152609e6020526040812080548390811061138d57fe5b6000918252602090912001546001600160a01b031690506113b86113b18983610866565b8590611eca565b935050600101611361565b506000806113d088612559565b909250905060006113e18584611eca565b6001600160a01b03999099166000908152609d6020526040902054999197509095505050505050565b6034546001600160a01b031661144f576040805162461bcd60e51b81526020600482015260056024820152640534f5f43360dc1b604482015290519081900360640190fd5b611457611c03565b6034546001600160a01b039081169116146114a2576040805162461bcd60e51b8152602060048201526006602482015265534f5f434e4360d01b604482015290519081900360640190fd5b6034546033546040516001600160a01b03928316929091169060008051602061327783398151915290600090a360348054603380546001600160a01b03199081166001600160a01b03841617909155169055565b6067546001600160a01b031690565b6001600160a01b0381166000908152609e6020526040812054818167ffffffffffffffff8111801561153657600080fd5b50604051908082528060200260200182016040528015611560578160200160208202803683370190505b5090506000805b83811015611660576001600160a01b0386166000908152609e6020526040812080548390811061159357fe5b60009182526020918290200154604080516347535d7b60e01b815290516001600160a01b03909216935083926347535d7b92600480840193829003018186803b1580156115df57600080fd5b505afa1580156115f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116179190612e39565b6116275750600190910190611658565b80848484038151811061163657fe5b60200260200101906001600160a01b031690816001600160a01b031681525050505b600101611567565b50609b54604051634dffaee560e01b81526001600160a01b0390911690634dffaee5906116939088908690600401612f9f565b60206040518083038186803b1580156116ab57600080fd5b505afa1580156116bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112739190612e39565b6001600160a01b039182166000908152609f6020908152604080832093909416825291909152206001015490565b611719611f2f565b610a6c8383836123ed565b6000610883610793609a60009054906101000a90046001600160a01b03166001600160a01b031663a85494026040518163ffffffff1660e01b815260040160206040518083038186803b15801561177a57600080fd5b505afa15801561178e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b29190612e7c565b6117bb85610e4a565b9061269d565b6117c9611f2f565b61108c828261243c565b6117db611f2f565b6001600160a01b0382166000908152609e602090815260409182902080548351818402810184019094528084529092611856929091849183018282801561184b57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161182d575b5050505050836126b2565b15611861575061108c565b8054600181018255600082815260209081902090910180546001600160a01b0319166001600160a01b0385811691909117909155609a5460408051631623e65d60e11b815290519190921692632c47ccba9260048082019391829003018186803b1580156118ce57600080fd5b505afa1580156118e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119069190612ee9565b60ff1681805490501115610a6c5760405162461bcd60e51b81526004016109eb906130e7565b609c546000906001600160a01b0316611943611c03565b6001600160a01b0316146119695760405162461bcd60e51b81526004016109eb9061315f565b506001600160a01b03166000908152609d60205260408120805491905590565b60008161199857506000610883565b60006119a384611c07565b905061087f6119b182611de6565b8490670de0b6b3a7640000611e32565b6000808212156119e1576119dc6119d7836126fe565b61272a565b610883565b6108838261272a565b600081611a3e576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b81600019148015611a525750600160ff1b83145b15611a8e5760405162461bcd60e51b81526004018080602001828103825260218152602001806132356021913960400191505060405180910390fd5b6000828481611a9957fe5b05949350505050565b600082611ab157506000610883565b82820282848281611abe57fe5b04146105ab5760405162461bcd60e51b81526004018080602001828103825260218152602001806132566021913960400191505060405180910390fd5b6000808060001985870986860292508281109083900303905080611b315760008411611b2657600080fd5b5082900490506105ab565b808411611b3d57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b8062ffffff811681146108065760405162461bcd60e51b81526004018080602001828103825260268152602001806132e36026913960400191505060405180910390fd5b60006105ab838362ffffff16620f4240611e32565b3390565b6000816001600160a01b03166347535d7b6040518163ffffffff1660e01b815260040160206040518083038186803b158015611c4257600080fd5b505afa158015611c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7a9190612e39565b15611c8f57611c8882612088565b9050610806565b816001600160a01b031663c2b6b58c6040518163ffffffff1660e01b815260040160206040518083038186803b158015611cc857600080fd5b505afa158015611cdc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d009190612e39565b611d7557816001600160a01b0316631c2ab4056040518163ffffffff1660e01b815260040160206040518083038186803b158015611d3d57600080fd5b505afa158015611d51573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc9190612e9f565b816001600160a01b03166357a48b016040518163ffffffff1660e01b815260040160206040518083038186803b158015611dae57600080fd5b505afa158015611dc2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108839190612e9f565b60006001600160ff1b03821115611e2e5760405162461bcd60e51b81526004018080602001828103825260288152602001806132976028913960400191505060405180910390fd5b5090565b60008060008512611e435784611e4c565b611e4c856126fe565b90506000808512611e5d5784611e66565b611e66856126fe565b905060008087128015611e795750600086135b80611e8f5750600087138015611e8f5750600086125b611e9a576000611e9d565b60015b90506000611eac848488611afb565b905081611ec157611ebc81611de6565b6105a4565b6105a481612781565b6000828201818312801590611edf5750838112155b80611ef45750600083128015611ef457508381125b6105ab5760405162461bcd60e51b81526004018080602001828103825260218152602001806131e66021913960400191505060405180910390fd5b6067546001600160a01b0316611f43611c03565b6001600160a01b031614611f695760405162461bcd60e51b81526004016109eb906130c6565b565b6001600160a01b038085166000908152609f6020908152604080832093871683529290529081208054829190611fa19086611eca565b81556001810154611fb29085611eca565b60018201819055905497909650945050505050565b6000611fd230611fd8565b15905090565b3b151590565b600054610100900460ff1680611ff75750611ff7611fc7565b80612005575060005460ff16155b6120405760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff1615801561206b576000805460ff1961ff0019909116610100171660011790555b612073612795565b8015612085576000805461ff00191690555b50565b609a546040805163b0a336a760e01b815281516000936001600160a01b03169284928392859263b0a336a79260048082019391829003018186803b1580156120cf57600080fd5b505afa1580156120e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121079190612eb7565b915091506000612118866000612884565b905060006121268785612884565b9050600061214761213a6107938a876129a2565b610dd96107938b88612884565b905060006121606119d78361126d6107938d60006129a2565b905061216d848483612a21565b9998505050505050505050565b6001600160a01b038083166000818152609f60209081526040808320948616835293815283822082815560018101839055600201829055918152609e909152908120805490915b818110156122a557836001600160a01b03168382815481106121df57fe5b6000918252602090912001546001600160a01b0316141561229d5760018203811461226c5782600183038154811061221357fe5b9060005260206000200160009054906101000a90046001600160a01b031683828154811061223d57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b8280548061227657fe5b600082815260209020810160001990810180546001600160a01b03191690550190556122a5565b6001016121c1565b5050505050565b801561108c576001600160a01b0382166000908152609d60205260409020546122d59082611eca565b6001600160a01b0383166000818152609d6020526040908190209290925590517febf4e69d81451d269fc4d9551b06d58bea2ed426d2c528919ce45f6070946efb9061232290849061305c565b60405180910390a25050565b60008183038183128015906123435750838113155b80612358575060008312801561235857508381135b6105ab5760405162461bcd60e51b81526004018080602001828103825260248152602001806132bf6024913960400191505060405180910390fd5b6000828201838110156105ab576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b8015610a6c576001600160a01b038084166000908152609f602090815260408083209386168352929052206001810154612427908361232e565b600182015561243684836122ac565b50505050565b6001600160a01b038083166000908152609f602090815260408083209385168352928152908290208251606081018452815480825260018301549382019390935260029091015492810192909252600a90612496906119c1565b1015806124b05750600a6124ad82602001516119c1565b10155b156124bb575061108c565b609b546040516321b499f560e11b81526000916001600160a01b03169063436933ea906124ee9087908790600401612f61565b60006040518083038186803b15801561250657600080fd5b505afa15801561251a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125429190810190612d8b565b51111561254f575061108c565b610a6c838361217a565b6001600160a01b0381166000908152609e602052604081205481908190815b818110156125f1576001600160a01b0386166000908152609e602052604081208054839081106125a457fe5b60009182526020808320909101546001600160a01b038a81168452609f83526040808520919092168085529252909120600101549091506125e6908590611eca565b935050600101612578565b50609b546001600160a01b038681166000908152609e6020526040808220905163d0581a9360e01b81529193929092169163d0581a9391612636918a91600401612fc3565b604080518083038186803b15801561264d57600080fd5b505afa158015612661573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126859190612e59565b945090506126938382611eca565b9450505050915091565b60006105ab838362ffffff16620f4240611afb565b6000805b83518110156111bd57826001600160a01b03168482815181106126d557fe5b60200260200101516001600160a01b031614156126f6576001915050610883565b6001016126b6565b6000600160ff1b82136127235760405162461bcd60e51b81526004016109eb90613107565b5060000390565b600080821215611e2e576040805162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015290519081900360640190fd5b600061278c82611de6565b60000392915050565b600054610100900460ff16806127ae57506127ae611fc7565b806127bc575060005460ff16155b6127f75760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff16158015612822576000805460ff1961ff0019909116610100171660011790555b61282a612a50565b6000612834611c03565b603380546001600160a01b0319166001600160a01b03831690811790915560405191925090600090600080516020613277833981519152908290a3508015612085576000805461ff001916905550565b60006105ab61299d609b60009054906101000a90046001600160a01b03166001600160a01b031663f807cd226040518163ffffffff1660e01b815260040160206040518083038186803b1580156128da57600080fd5b505afa1580156128ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129129190612c2f565b6001600160a01b031663dc7e7e1686866040518363ffffffff1660e01b815260040161293f92919061301f565b60206040518083038186803b15801561295757600080fd5b505afa15801561296b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061298f9190612c2f565b6001600160a01b0316612ae5565b612aff565b604051631208064760e01b81526000906001600160a01b038416906312080647906129d19085906004016131bf565b60206040518083038186803b1580156129e957600080fd5b505afa1580156129fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ab9190612e9f565b6000612a48612a308585612b18565b612a43612a3d8787612b2e565b85612b18565b612b2e565b949350505050565b600054610100900460ff1680612a695750612a69611fc7565b80612a77575060005460ff16155b612ab25760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff16158015612add576000805460ff1961ff0019909116610100171660011790555b612073612b3e565b60006108836001600160a01b03831680600160601b611afb565b600061088382670de0b6b3a7640000600160601b611afb565b6000818310612b2757816105ab565b5090919050565b600081831015612b2757816105ab565b600054610100900460ff1680612b575750612b57611fc7565b80612b65575060005460ff16155b612ba05760405162461bcd60e51b815260040180806020018281038252602e815260200180613207602e913960400191505060405180910390fd5b600054610100900460ff16158015612073576000805460ff1961ff0019909116610100171660011790558015612085576000805461ff001916905550565b60405180606001604052806000815260200160008152602001600081525090565b805163ffffffff8116811461080657600080fd5b600060208284031215612c24578081fd5b81356105ab816131d0565b600060208284031215612c40578081fd5b81516105ab816131d0565b60008060408385031215612c5d578081fd5b8235612c68816131d0565b91506020830135612c78816131d0565b809150509250929050565b600080600060608486031215612c97578081fd5b8335612ca2816131d0565b92506020840135612cb2816131d0565b929592945050506040919091013590565b60008060008060808587031215612cd8578081fd5b8435612ce3816131d0565b93506020850135612cf3816131d0565b93969395505050506040820135916060013590565b60008060008060008060c08789031215612d20578182fd5b8635612d2b816131d0565b95506020870135612d3b816131d0565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60008060408385031215612d72578182fd5b8235612d7d816131d0565b946020939093013593505050565b60006020808385031215612d9d578182fd5b825167ffffffffffffffff80821115612db4578384fd5b818501915085601f830112612dc7578384fd5b815181811115612dd357fe5b83810260405185828201018181108582111715612dec57fe5b604052828152858101935084860182860187018a1015612e0a578788fd5b8795505b83861015612e2c578051855260019590950194938601938601612e0e565b5098975050505050505050565b600060208284031215612e4a578081fd5b815180151581146105ab578182fd5b60008060408385031215612e6b578182fd5b505080516020909101519092909150565b600060208284031215612e8d578081fd5b815162ffffff811681146105ab578182fd5b600060208284031215612eb0578081fd5b5051919050565b60008060408385031215612ec9578182fd5b612ed283612bff565b9150612ee060208401612bff565b90509250929050565b600060208284031215612efa578081fd5b815160ff811681146105ab578182fd5b6000815180845260208085019450808401835b83811015612f425781516001600160a01b031687529582019590820190600101612f1d565b509495945050505050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152901515604082015260600190565b6001600160a01b0383168152604060208201819052600090612a4890830184612f0a565b60006040820160018060a01b03808616845260206040818601528286548085526060870191508786528286209450855b81811015613011578554851683526001958601959284019201612ff3565b509098975050505050505050565b6001600160a01b0392909216825263ffffffff16602082015260400190565b6000602082526105ab6020830184612f0a565b901515815260200190565b90815260200190565b918252602082015260400190565b93845260208401929092526040830152606082015260800190565b9283526020830191909152604082015260600190565b60208082526008908201526741425f4348434e4360c01b604082015260600190565b6020808252600790820152660869088be9e86960cb1b604082015260600190565b60208082526006908201526541425f4d4e4560d01b604082015260600190565b6020808252601c908201527f506572704d6174683a20696e76657273696f6e206f766572666c6f7700000000604082015260600190565b60208082526007908201526641425f4f424e4360c81b604082015260600190565b60208082526005908201526420a12fa7ab60d91b604082015260600190565b60208082526006908201526541425f564e4360d01b604082015260600190565b81518152602080830151908201526040918201519181019190915260600190565b63ffffffff91909116815260200190565b6001600160a01b038116811461208557600080fdfe5369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65645369676e6564536166654d6174683a206469766973696f6e206f766572666c6f77536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f778be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e053616665436173743a2076616c756520646f65736e27742066697420696e20616e20696e743235365369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f7753616665436173743a2076616c756520646f65736e27742066697420696e2032342062697473a2646970667358221220b010e2662ad64fe701c27bb65d03befe32d9abc4855914cd66e6b619bcb9416f64736f6c63430007060033
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.