Transactions
Internal Transactions
Coin Balance History
Code
Read Contract
Read Proxy
Write Contract
Write Proxy
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- KccDexAggregatorV1
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 200
- Verified at
- 2022-03-31T10:32:38.661911Z
project:/contracts/dex/kcc/KccDexAggregatorV1.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; import "./KccUniV2Dex.sol"; import "../DexAggregatorInterface.sol"; import "../../lib/DexData.sol"; import "../../lib/Utils.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; import "../../DelegateInterface.sol"; import "../../Adminable.sol"; /// @title Swap logic on KCC /// @author OpenLeverage /// @notice Use this contract to swap tokens. /// @dev Routers for different swap requests. contract KccDexAggregatorV1 is DelegateInterface, Adminable, DexAggregatorInterface, KccUniV2Dex { using DexData for bytes; using SafeMath for uint; mapping(IUniswapV2Pair => V2PriceOracle) public uniV2PriceOracle; IUniswapV2Factory public mojitoFactory; address public openLev; uint8 private constant priceDecimals = 18; mapping(uint8 => DexInfo) public dexInfo; //mojitoSwapFactory: 0x79855A03426e15Ad120df77eFA623aF87bd54eF3 、kuSwapFactory: 0xAE46cBBCDFBa3bE0F02F463Ec5486eBB4e2e65Ae function initialize( IUniswapV2Factory _mojitoFactory, address _unusedFactory ) public { require(msg.sender == admin, "Not admin"); _unusedFactory; mojitoFactory = _mojitoFactory; dexInfo[DexData.DEX_MOJITO] = DexInfo(_mojitoFactory, 30); } /// @notice Save factories of the dex. /// @param dexName Index of Dex. find list of dex in contracts/lib/DexData.sol. /// @param factoryAddr Factory address of Different dex forked from uniswap. /// @param fees Swap fee collects by. function setDexInfo(uint8[] memory dexName, IUniswapV2Factory[] memory factoryAddr, uint16[] memory fees) external override onlyAdmin { require(dexName.length == factoryAddr.length && dexName.length == fees.length, 'EOR'); for (uint i = 0; i < dexName.length; i++) { dexInfo[dexName[i]] = DexInfo(factoryAddr[i], fees[i]); } } /// @dev SetOpenlev address to update dex price function setOpenLev(address _openLev) external onlyAdmin { require(address(0) != _openLev, '0x'); openLev = _openLev; } /// @notice Sell tokens /// @dev Sell exact amount of token with tax applied /// @param buyToken Address of token transfer from Dex pair /// @param sellToken Address of token transfer into Dex pair /// @param sellAmount Exact amount to sell /// @param minBuyAmount minmum amount of token to receive. /// @param data Dex to use for swap /// @return buyAmount Exact Amount bought function sell(address buyToken, address sellToken, uint sellAmount, uint minBuyAmount, bytes memory data) external override returns (uint buyAmount){ address payer = msg.sender; buyAmount = uniClassSell(dexInfo[data.toDex()], buyToken, sellToken, sellAmount, minBuyAmount, payer, payer); } /// @notice Sell tokens /// @dev Sell exact amount of token through path /// @param sellAmount Exact amount to sell /// @param minBuyAmount minmum amount of token to receive. /// @param data Dex to use for swap and path of the swap /// @return buyAmount Exact amount bought function sellMul(uint sellAmount, uint minBuyAmount, bytes memory data) external override returns (uint buyAmount){ buyAmount = uniClassSellMul(dexInfo[data.toDex()], sellAmount, minBuyAmount, data.toUniV2Path()); } /// @notice Buy tokens /// @dev Buy exact amount of token with tax applied /// @param buyToken Address of token transfer from Dex pair /// @param sellToken Address of token transfer into Dex pair /// @param buyTax Tax applyed by buyToken while transfer from Dex pair /// @param sellTax Tax applyed by sellToken while transfer into Dex pair /// @param buyAmount Exact amount to buy /// @param maxSellAmount maximum amount of token to receive. /// @param data Dex to use for swap /// @return sellAmount Exact amount sold function buy(address buyToken, address sellToken, uint24 buyTax, uint24 sellTax, uint buyAmount, uint maxSellAmount, bytes memory data) external override returns (uint sellAmount){ sellAmount = uniClassBuy(dexInfo[data.toDex()], buyToken, sellToken, buyAmount, maxSellAmount, buyTax, sellTax); } /// @notice Calculate amount of token to buy /// @dev Calculate exact amount of token to buy with tax applied /// @param buyToken Address of token transfer from Dex pair /// @param sellToken Address of token transfer into Dex pair /// @param buyTax Tax applyed by buyToken while transfer from Dex pair /// @param sellTax Tax applyed by sellToken while transfer into Dex pair /// @param sellAmount Exact amount to sell /// @param data Dex to use for swap /// @return buyAmount Amount of buyToken would bought function calBuyAmount(address buyToken, address sellToken, uint24 buyTax, uint24 sellTax, uint sellAmount, bytes memory data) external view override returns (uint buyAmount) { sellAmount = Utils.toAmountAfterTax(sellAmount, sellTax); buyAmount = uniClassCalBuyAmount(dexInfo[data.toDex()], buyToken, sellToken, sellAmount); buyAmount = Utils.toAmountAfterTax(buyAmount, buyTax); } /// @notice Calculate amount of token to sell /// @dev Calculate exact amount of token to sell with tax applied /// @param buyToken Address of token transfer from Dex pair /// @param sellToken Address of token transfer into Dex pair /// @param buyTax Tax applyed by buyToken while transfer from Dex pair /// @param sellTax Tax applyed by SellToken while transfer into Dex pair /// @param buyAmount Exact amount to buy /// @param data Dex to use for swap /// @return sellAmount Amount of sellToken would sold function calSellAmount(address buyToken, address sellToken, uint24 buyTax, uint24 sellTax, uint buyAmount, bytes memory data) external view override returns (uint sellAmount){ sellAmount = uniClassCalSellAmount(dexInfo[data.toDex()], buyToken, sellToken, buyAmount, buyTax, sellTax); } /// @notice Get price /// @dev Get current price of desToken / quoteToken /// @param desToken Token to be priced /// @param quoteToken Token used for pricing /// @param data Dex to use for swap function getPrice(address desToken, address quoteToken, bytes memory data) external view override returns (uint256 price, uint8 decimals){ decimals = priceDecimals; price = uniClassGetPrice(dexInfo[data.toDex()].factory, desToken, quoteToken, decimals); } /// @dev Get average price of desToken / quoteToken in the last period of time /// @param desToken Token to be priced /// @param quoteToken Token used for pricing /// @param secondsAgo Time period of the average /// @param data Dex to use for swap function getAvgPrice(address desToken, address quoteToken, uint32 secondsAgo, bytes memory data) external view override returns (uint256 price, uint8 decimals, uint256 timestamp){ require(data.isUniV2Class(), "unsupported dex"); // Shh - currently unused secondsAgo; decimals = priceDecimals; address pair = getUniClassPair(desToken, quoteToken, dexInfo[data.toDex()].factory); V2PriceOracle memory priceOracle = uniV2PriceOracle[IUniswapV2Pair(pair)]; (price, timestamp) = uniClassGetAvgPrice(desToken, quoteToken, priceOracle); } /// @notice Fet current and history price /// @param desToken Token to be priced /// @param quoteToken Token used for pricing /// @param secondsAgo not used on BSC /// @param dexData dex parameters /// @return price Real-time price /// @return cAvgPrice Current TWAP price /// @return hAvgPrice Historical TWAP price /// @return decimals Token price decimal /// @return timestamp Last TWAP price update timestamp function getPriceCAvgPriceHAvgPrice( address desToken, address quoteToken, uint32 secondsAgo, bytes memory dexData ) external view override returns (uint price, uint cAvgPrice, uint256 hAvgPrice, uint8 decimals, uint256 timestamp){ require(dexData.isUniV2Class(), "unsupported dex"); secondsAgo; decimals = priceDecimals; address pair = getUniClassPair(desToken, quoteToken, dexInfo[dexData.toDex()].factory); V2PriceOracle memory priceOracle = uniV2PriceOracle[IUniswapV2Pair(pair)]; (price, cAvgPrice, hAvgPrice, timestamp) = uniClassGetPriceCAvgPriceHAvgPrice(pair, priceOracle, desToken, quoteToken, decimals); } /// @dev Update Dex price if not updated over time window /// @param desToken Token to be priced /// @param quoteToken Token used for pricing /// @param timeWindow minmum time gap between two updates /// @param data dex parameters /// @return If updated function updatePriceOracle(address desToken, address quoteToken, uint32 timeWindow, bytes memory data) external override returns (bool){ require(msg.sender == openLev, "Only openLev can update price"); require(data.isUniV2Class(), "unsupported dex"); address pair = getUniClassPair(desToken, quoteToken, dexInfo[data.toDex()].factory); V2PriceOracle memory priceOracle = uniV2PriceOracle[IUniswapV2Pair(pair)]; (V2PriceOracle memory updatedPriceOracle, bool updated) = uniClassUpdatePriceOracle(pair, priceOracle, timeWindow, priceDecimals); if (updated) { uniV2PriceOracle[IUniswapV2Pair(pair)] = updatedPriceOracle; } return updated; } /// @dev Update UniV3 observations /// @param desToken Token to be priced /// @param quoteToken Token used for pricing /// @param data Dex parameters function updateV3Observation(address desToken, address quoteToken, bytes memory data) external pure override { // Shh - currently unused (desToken,quoteToken, data); revert("Not implemented"); } }
project:/contracts/lib/Utils.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.7.6; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; library Utils{ using SafeMath for uint; uint constant feeRatePrecision = 10**6; function toAmountBeforeTax(uint256 amount, uint24 feeRate) internal pure returns (uint){ uint denominator = feeRatePrecision.sub(feeRate); uint numerator = amount.mul(feeRatePrecision).add(denominator).sub(1); return numerator / denominator; } function toAmountAfterTax(uint256 amount, uint24 feeRate) internal pure returns (uint){ return amount.mul(feeRatePrecision.sub(feeRate)) / feeRatePrecision; } function minOf(uint a, uint b) internal pure returns (uint){ return a < b ? a : b; } function maxOf(uint a, uint b) internal pure returns (uint){ return a > b ? a : b; } }
@openzeppelin/contracts/math/SafeMath.sol
// 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 SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol
pragma solidity >=0.5.0; interface IUniswapV2Factory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }
@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
project:/contracts/Adminable.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.6; abstract contract Adminable { address payable public admin; address payable public pendingAdmin; address payable public developer; event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); event NewAdmin(address oldAdmin, address newAdmin); constructor () { developer = msg.sender; } modifier onlyAdmin() { require(msg.sender == admin, "caller must be admin"); _; } modifier onlyAdminOrDeveloper() { require(msg.sender == admin || msg.sender == developer, "caller must be admin or developer"); _; } function setPendingAdmin(address payable newPendingAdmin) external virtual onlyAdmin { // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); } function acceptAdmin() external virtual { require(msg.sender == pendingAdmin, "only pendingAdmin can accept admin"); // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); } }
project:/contracts/DelegateInterface.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.6; contract DelegateInterface { /** * Implementation address for this contract */ address public implementation; }
project:/contracts/dex/DexAggregatorInterface.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; interface DexAggregatorInterface { function sell(address buyToken, address sellToken, uint sellAmount, uint minBuyAmount, bytes memory data) external returns (uint buyAmount); function sellMul(uint sellAmount, uint minBuyAmount, bytes memory data) external returns (uint buyAmount); function buy(address buyToken, address sellToken, uint24 buyTax, uint24 sellTax, uint buyAmount, uint maxSellAmount, bytes memory data) external returns (uint sellAmount); function calBuyAmount(address buyToken, address sellToken, uint24 buyTax, uint24 sellTax, uint sellAmount, bytes memory data) external view returns (uint); function calSellAmount(address buyToken, address sellToken, uint24 buyTax, uint24 sellTax, uint buyAmount, bytes memory data) external view returns (uint); function getPrice(address desToken, address quoteToken, bytes memory data) external view returns (uint256 price, uint8 decimals); function getAvgPrice(address desToken, address quoteToken, uint32 secondsAgo, bytes memory data) external view returns (uint256 price, uint8 decimals, uint256 timestamp); //cal current avg price and get history avg price function getPriceCAvgPriceHAvgPrice(address desToken, address quoteToken, uint32 secondsAgo, bytes memory dexData) external view returns (uint price, uint cAvgPrice, uint256 hAvgPrice, uint8 decimals, uint256 timestamp); function updatePriceOracle(address desToken, address quoteToken, uint32 timeWindow, bytes memory data) external returns(bool); function updateV3Observation(address desToken, address quoteToken, bytes memory data) external; function setDexInfo(uint8[] memory dexName, IUniswapV2Factory[] memory factoryAddr, uint16[] memory fees) external; }
project:/contracts/dex/kcc/KccUniV2Dex.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.6; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol"; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "../../lib/TransferHelper.sol"; import "../../lib/DexData.sol"; import "../../lib/Utils.sol"; contract KccUniV2Dex { using SafeMath for uint; using Utils for uint; using TransferHelper for IERC20; struct V2PriceOracle { uint32 blockTimestampLast; // Last block timestamp when price updated uint price0; // recorded price for token0 uint price1; // recorded price for token1 uint price0CumulativeLast; // Cumulative TWAP for token0 uint price1CumulativeLast; // Cumulative TWAP for token1 } struct DexInfo { IUniswapV2Factory factory; uint16 fees; } function uniClassSell(DexInfo memory dexInfo, address buyToken, address sellToken, uint sellAmount, uint minBuyAmount, address payer, address payee ) internal returns (uint buyAmount){ address pair = getUniClassPair(buyToken, sellToken, dexInfo.factory); IUniswapV2Pair(pair).sync(); sellAmount = transferOut(IERC20(sellToken), payer, pair, sellAmount); (uint256 token0Reserves, uint256 token1Reserves,) = IUniswapV2Pair(pair).getReserves(); sellAmount = buyToken < sellToken ? IERC20(sellToken).balanceOf(pair).sub(token1Reserves) : IERC20(sellToken).balanceOf(pair).sub(token0Reserves); uint balanceBefore = IERC20(buyToken).balanceOf(payee); dexInfo.fees = getPairFees(dexInfo, pair); if (buyToken < sellToken) { buyAmount = getAmountOut(sellAmount, token1Reserves, token0Reserves, dexInfo.fees); IUniswapV2Pair(pair).swap(buyAmount, 0, payee, ""); } else { buyAmount = getAmountOut(sellAmount, token0Reserves, token1Reserves, dexInfo.fees); IUniswapV2Pair(pair).swap(0, buyAmount, payee, ""); } buyAmount = IERC20(buyToken).balanceOf(payee).sub(balanceBefore); require(buyAmount >= minBuyAmount, 'buy amount less than min'); } function uniClassSellMul(DexInfo memory dexInfo, uint sellAmount, uint minBuyAmount, address[] memory tokens) internal returns (uint buyAmount){ for (uint i = 1; i < tokens.length; i++) { address sellToken = tokens[i - 1]; address buyToken = tokens[i]; bool isLast = i == tokens.length - 1; address payer = i == 1 ? msg.sender : address(this); address payee = isLast ? msg.sender : address(this); buyAmount = uniClassSell(dexInfo, buyToken, sellToken, sellAmount, 0, payer, payee); if (!isLast) { sellAmount = buyAmount; } } require(buyAmount >= minBuyAmount, 'buy amount less than min'); } function uniClassBuy( DexInfo memory dexInfo, address buyToken, address sellToken, uint buyAmount, uint maxSellAmount, uint24 buyTokenFeeRate, uint24 sellTokenFeeRate) internal returns (uint sellAmount){ address pair = getUniClassPair(buyToken, sellToken, dexInfo.factory); IUniswapV2Pair(pair).sync(); (uint256 token0Reserves, uint256 token1Reserves,) = IUniswapV2Pair(pair).getReserves(); uint balanceBefore = IERC20(buyToken).balanceOf(msg.sender); dexInfo.fees = getPairFees(dexInfo, pair); if (buyToken < sellToken) { sellAmount = getAmountIn(buyAmount.toAmountBeforeTax(buyTokenFeeRate), token1Reserves, token0Reserves, dexInfo.fees); sellAmount = sellAmount.toAmountBeforeTax(sellTokenFeeRate); require(sellAmount <= maxSellAmount, 'sell amount not enough'); transferOut(IERC20(sellToken), msg.sender, pair, sellAmount); IUniswapV2Pair(pair).swap(buyAmount.toAmountBeforeTax(buyTokenFeeRate), 0, msg.sender, ""); } else { sellAmount = getAmountIn(buyAmount.toAmountBeforeTax(buyTokenFeeRate), token0Reserves, token1Reserves, dexInfo.fees); sellAmount = sellAmount.toAmountBeforeTax(sellTokenFeeRate); require(sellAmount <= maxSellAmount, 'sell amount not enough'); transferOut(IERC20(sellToken), msg.sender, pair, sellAmount); IUniswapV2Pair(pair).swap(0, buyAmount.toAmountBeforeTax(buyTokenFeeRate), msg.sender, ""); } uint balanceAfter = IERC20(buyToken).balanceOf(msg.sender); require(buyAmount <= balanceAfter.sub(balanceBefore), "wrong amount bought"); } function uniClassCalBuyAmount(DexInfo memory dexInfo, address buyToken, address sellToken, uint sellAmount) internal view returns (uint) { address pair = getUniClassPair(buyToken, sellToken, dexInfo.factory); (uint256 token0Reserves, uint256 token1Reserves,) = IUniswapV2Pair(pair).getReserves(); if (buyToken < sellToken) { return getAmountOut(sellAmount, token1Reserves, token0Reserves, getPairFees(dexInfo, pair)); } else { return getAmountOut(sellAmount, token0Reserves, token1Reserves, getPairFees(dexInfo, pair)); } } function uniClassCalSellAmount( DexInfo memory dexInfo, address buyToken, address sellToken, uint buyAmount, uint24 buyTokenFeeRate, uint24 sellTokenFeeRate) internal view returns (uint sellAmount) { address pair = getUniClassPair(buyToken, sellToken, dexInfo.factory); (uint256 token0Reserves, uint256 token1Reserves,) = IUniswapV2Pair(pair).getReserves(); sellAmount = buyToken < sellToken ? getAmountIn(buyAmount.toAmountBeforeTax(buyTokenFeeRate), token1Reserves, token0Reserves, getPairFees(dexInfo, pair)) : getAmountIn(buyAmount.toAmountBeforeTax(buyTokenFeeRate), token0Reserves, token1Reserves, getPairFees(dexInfo, pair)); return sellAmount.toAmountBeforeTax(sellTokenFeeRate); } function uniClassGetPrice(IUniswapV2Factory factory, address desToken, address quoteToken, uint8 decimals) internal view returns (uint256){ address pair = getUniClassPair(desToken, quoteToken, factory); (uint256 token0Reserves, uint256 token1Reserves,) = IUniswapV2Pair(pair).getReserves(); return desToken == IUniswapV2Pair(pair).token0() ? token1Reserves.mul(10 ** decimals).div(token0Reserves) : token0Reserves.mul(10 ** decimals).div(token1Reserves); } function uniClassGetAvgPrice(address desToken, address quoteToken, V2PriceOracle memory priceOracle) internal pure returns (uint256 price, uint256 timestamp){ timestamp = priceOracle.blockTimestampLast; price = desToken < quoteToken ? uint(priceOracle.price0) : uint(priceOracle.price1); } function uniClassGetPriceCAvgPriceHAvgPrice(address pair, V2PriceOracle memory priceOracle, address desToken, address quoteToken, uint8 decimals) internal view returns (uint price, uint cAvgPrice, uint256 hAvgPrice, uint256 timestamp){ bool isToken0 = desToken < quoteToken; (uint256 token0Reserves, uint256 token1Reserves, uint32 uniBlockTimeLast) = IUniswapV2Pair(pair).getReserves(); price = isToken0 ? token1Reserves.mul(10 ** decimals).div(token0Reserves) : token0Reserves.mul(10 ** decimals).div(token1Reserves); hAvgPrice = isToken0 ? uint(priceOracle.price0) : uint(priceOracle.price1); timestamp = priceOracle.blockTimestampLast; if (uniBlockTimeLast <= priceOracle.blockTimestampLast) { cAvgPrice = hAvgPrice; } else { uint32 timeElapsed = uniBlockTimeLast - priceOracle.blockTimestampLast; cAvgPrice = uint256(isToken0 ? calTPrice(IUniswapV2Pair(pair).price0CumulativeLast(), priceOracle.price0CumulativeLast, timeElapsed, decimals) : calTPrice(IUniswapV2Pair(pair).price1CumulativeLast(), priceOracle.price1CumulativeLast, timeElapsed, decimals)); } } function uniClassUpdatePriceOracle(address pair, V2PriceOracle memory priceOracle, uint32 timeWindow, uint8 decimals) internal returns (V2PriceOracle memory, bool updated) { uint32 currentBlockTime = toUint32(block.timestamp); if (currentBlockTime < (priceOracle.blockTimestampLast + timeWindow)) { return (priceOracle, false); } IUniswapV2Pair(pair).sync(); uint32 timeElapsed = currentBlockTime - priceOracle.blockTimestampLast; uint currentPrice0CumulativeLast = IUniswapV2Pair(pair).price0CumulativeLast(); uint currentPrice1CumulativeLast = IUniswapV2Pair(pair).price1CumulativeLast(); if (priceOracle.blockTimestampLast != 0) { priceOracle.price0 = calTPrice(currentPrice0CumulativeLast, priceOracle.price0CumulativeLast, timeElapsed, decimals); priceOracle.price1 = calTPrice(currentPrice1CumulativeLast, priceOracle.price1CumulativeLast, timeElapsed, decimals); } priceOracle.price0CumulativeLast = currentPrice0CumulativeLast; priceOracle.price1CumulativeLast = currentPrice1CumulativeLast; priceOracle.blockTimestampLast = currentBlockTime; return (priceOracle, true); } function calTPrice(uint currentPriceCumulativeLast, uint historyPriceCumulativeLast, uint32 timeElapsed, uint8 decimals) internal pure returns (uint){ return ((currentPriceCumulativeLast.sub(historyPriceCumulativeLast).mul(10 ** decimals)) >> 112).div(timeElapsed); } function toUint32(uint256 y) internal pure returns (uint32 z) { require((z = uint32(y)) == y); } function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut, uint16 fees) private pure returns (uint amountOut) { require(amountIn > 0, 'INSUFFICIENT_INPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'INSUFFICIENT_LIQUIDITY'); uint amountInWithFee = amountIn.mul(uint(10000).sub(fees)); uint numerator = amountInWithFee.mul(reserveOut); uint denominator = reserveIn.mul(10000).add(amountInWithFee); amountOut = numerator / denominator; } function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut, uint16 fees) private pure returns (uint amountIn) { require(amountOut > 0, 'INSUFFICIENT_OUTPUT_AMOUNT'); require(reserveIn > 0 && reserveOut > 0, 'INSUFFICIENT_LIQUIDITY'); uint numerator = reserveIn.mul(amountOut).mul(10000); uint denominator = reserveOut.sub(amountOut).mul(uint(10000).sub(fees)); amountIn = (numerator / denominator).add(1); } function transferOut(IERC20 token, address payer, address to, uint amount) private returns (uint256 amountReceived) { if (payer == address(this)) { amountReceived = token.safeTransfer(to, amount); } else { amountReceived = token.safeTransferFrom(payer, to, amount); } } function getUniClassPair(address tokenA, address tokenB, IUniswapV2Factory factory) internal view returns (address pair){ (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); if (address(factory) == 0x79855A03426e15Ad120df77eFA623aF87bd54eF3) { // mojito return address(uint(keccak256(abi.encodePacked( hex'ff', address(factory), keccak256(abi.encodePacked(token0, token1)), hex'3b58864b0ea7cc084fc3a5dc3ca7ea2fb5cedd9aac7f9fff0c3dd9a15713f1c7' )))); } else if (address(factory) == 0xAE46cBBCDFBa3bE0F02F463Ec5486eBB4e2e65Ae) { // ku return address(uint(keccak256(abi.encodePacked( hex'ff', address(factory), keccak256(abi.encodePacked(token0, token1)), hex'5d71f8561d80ed979ca73d5b742278f4719baab5f0dd78b6ca91bec31f0e2dbc' )))); } else { return factory.getPair(tokenA, tokenB); } } function getPairFees(DexInfo memory dexInfo, address pair) private view returns (uint16){ if (address(dexInfo.factory) == 0x79855A03426e15Ad120df77eFA623aF87bd54eF3) { // mojito return toUint16((IMojitoPair)(pair).swapFeeNumerator()); } else if (address(dexInfo.factory) == 0xAE46cBBCDFBa3bE0F02F463Ec5486eBB4e2e65Ae) { // ku return toUint16((uint(10)).mul((IKuswapPair)(pair).swapFee())); } else { return dexInfo.fees; } } function toUint16(uint256 y) internal pure returns (uint16 z) { require((z = uint16(y)) == y); } } interface IMojitoPair { function swapFeeNumerator() external view returns (uint); } interface IKuswapPair { function swapFee() external view returns (uint32); }
project:/contracts/lib/DexData.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.7.6; pragma experimental ABIEncoderV2; /// @dev DexDataFormat addPair = byte(dexID) + bytes3(feeRate) + bytes(arrayLength) + byte3[arrayLength](trasferFeeRate Lpool <-> openlev) /// + byte3[arrayLength](transferFeeRate openLev -> Dex) + byte3[arrayLength](Dex -> transferFeeRate openLev) /// exp: 0x0100000002011170000000011170000000011170000000 /// DexDataFormat dexdata = byte(dexID)+ bytes3(feeRate) + byte(arrayLength) + path /// uniV2Path = bytes20[arraylength](address) /// uniV3Path = bytes20(address)+ bytes20[arraylength-1](address + fee) library DexData { // in byte uint constant DEX_INDEX = 0; uint constant FEE_INDEX = 1; uint constant ARRYLENTH_INDEX = 4; uint constant TRANSFERFEE_INDEX = 5; uint constant PATH_INDEX = 5; uint constant FEE_SIZE = 3; uint constant ADDRESS_SIZE = 20; uint constant NEXT_OFFSET = ADDRESS_SIZE + FEE_SIZE; uint8 constant DEX_UNIV2 = 1; uint8 constant DEX_UNIV3 = 2; uint8 constant DEX_PANCAKE = 3; uint8 constant DEX_SUSHI = 4; uint8 constant DEX_MDEX = 5; uint8 constant DEX_TRADERJOE = 6; uint8 constant DEX_SPOOKY = 7; uint8 constant DEX_QUICK = 8; uint8 constant DEX_SHIBA = 9; uint8 constant DEX_APE = 10; uint8 constant DEX_PANCAKEV1 = 11; uint8 constant DEX_BABY = 12; uint8 constant DEX_MOJITO = 13; uint8 constant DEX_KU = 14; struct V3PoolData { address tokenA; address tokenB; uint24 fee; } function toDex(bytes memory data) internal pure returns (uint8) { require(data.length >= FEE_INDEX, "DexData: toDex wrong data format"); uint8 temp; assembly { temp := byte(0, mload(add(data, add(0x20, DEX_INDEX)))) } return temp; } function toFee(bytes memory data) internal pure returns (uint24) { require(data.length >= ARRYLENTH_INDEX, "DexData: toFee wrong data format"); uint temp; assembly { temp := mload(add(data, add(0x20, FEE_INDEX))) } return uint24(temp >> (256 - (ARRYLENTH_INDEX - FEE_INDEX) * 8)); } function toDexDetail(bytes memory data) internal pure returns (uint32) { require (data.length >= FEE_INDEX, "DexData: toDexDetail wrong data format"); if (isUniV2Class(data)){ uint8 temp; assembly { temp := byte(0, mload(add(data, add(0x20, DEX_INDEX)))) } return uint32(temp); } else { uint temp; assembly { temp := mload(add(data, add(0x20, DEX_INDEX))) } return uint32(temp >> (256 - ((FEE_SIZE + FEE_INDEX) * 8))); } } function toArrayLength(bytes memory data) internal pure returns(uint8 length){ require(data.length >= TRANSFERFEE_INDEX, "DexData: toArrayLength wrong data format"); assembly { length := byte(0, mload(add(data, add(0x20, ARRYLENTH_INDEX)))) } } // only for add pair function toTransferFeeRates(bytes memory data) internal pure returns (uint24[] memory transferFeeRates){ uint8 length = toArrayLength(data) * 3; uint start = TRANSFERFEE_INDEX; transferFeeRates = new uint24[](length); for (uint i = 0; i < length; i++){ // use default value if (data.length <= start){ transferFeeRates[i] = 0; continue; } // use input value uint temp; assembly { temp := mload(add(data, add(0x20, start))) } transferFeeRates[i] = uint24(temp >> (256 - FEE_SIZE * 8)); start += FEE_SIZE; } } function toUniV2Path(bytes memory data) internal pure returns (address[] memory path) { uint8 length = toArrayLength(data); uint end = PATH_INDEX + ADDRESS_SIZE * length; require(data.length >= end, "DexData: toUniV2Path wrong data format"); uint start = PATH_INDEX; path = new address[](length); for (uint i = 0; i < length; i++) { uint startIndex = start + ADDRESS_SIZE * i; uint temp; assembly { temp := mload(add(data, add(0x20, startIndex))) } path[i] = address(temp >> (256 - ADDRESS_SIZE * 8)); } } function isUniV2Class(bytes memory data) internal pure returns(bool){ return toDex(data) != DEX_UNIV3; } function toUniV3Path(bytes memory data) internal pure returns (V3PoolData[] memory path) { uint8 length = toArrayLength(data); uint end = PATH_INDEX + (FEE_SIZE + ADDRESS_SIZE) * length - FEE_SIZE; require(data.length >= end, "DexData: toUniV3Path wrong data format"); require(length > 1, "DexData: toUniV3Path path too short"); uint temp; uint index = PATH_INDEX; path = new V3PoolData[](length - 1); for (uint i = 0; i < length - 1; i++) { V3PoolData memory pool; // get tokenA if (i == 0) { assembly { temp := mload(add(data, add(0x20, index))) } pool.tokenA = address(temp >> (256 - ADDRESS_SIZE * 8)); index += ADDRESS_SIZE; }else{ pool.tokenA = path[i-1].tokenB; index += NEXT_OFFSET; } // get TokenB assembly { temp := mload(add(data, add(0x20, index))) } uint tokenBAndFee = temp >> (256 - NEXT_OFFSET * 8); pool.tokenB = address(tokenBAndFee >> (FEE_SIZE * 8)); pool.fee = uint24(tokenBAndFee - (tokenBAndFee << (FEE_SIZE * 8))); path[i] = pool; } } }
project:/contracts/lib/TransferHelper.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.7.6; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // import "@openzeppelin/contracts/math/SafeMath.sol"; /** * @title TransferHelper * @dev Wrappers around ERC20 operations that returns the value received by recipent and the actual allowance of approval. * To use this library you can add a `using TransferHelper for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library TransferHelper{ // using SafeMath for uint; function safeTransfer(IERC20 _token, address _to, uint _amount) internal returns (uint amountReceived){ if (_amount > 0){ uint balanceBefore = _token.balanceOf(_to); address(_token).call(abi.encodeWithSelector(_token.transfer.selector, _to, _amount)); uint balanceAfter = _token.balanceOf(_to); require(balanceAfter > balanceBefore, "TF"); amountReceived = balanceAfter - balanceBefore; } } function safeTransferFrom(IERC20 _token, address _from, address _to, uint _amount) internal returns (uint amountReceived){ if (_amount > 0){ uint balanceBefore = _token.balanceOf(_to); address(_token).call(abi.encodeWithSelector(_token.transferFrom.selector, _from, _to, _amount)); // _token.transferFrom(_from, _to, _amount); uint balanceAfter = _token.balanceOf(_to); require(balanceAfter > balanceBefore, "TFF"); amountReceived = balanceAfter - balanceBefore; } } function safeApprove(IERC20 _token, address _spender, uint256 _amount) internal returns (uint) { bool success; if (_token.allowance(address(this), _spender) != 0){ (success, ) = address(_token).call(abi.encodeWithSelector(_token.approve.selector, _spender, 0)); require(success, "AF"); } (success, ) = address(_token).call(abi.encodeWithSelector(_token.approve.selector, _spender, _amount)); require(success, "AF"); return _token.allowance(address(this), _spender); } // function safeIncreaseAllowance(IERC20 _token, address _spender, uint256 _amount) internal returns (uint) { // uint256 allowanceBefore = _token.allowance(address(this), _spender); // uint256 allowanceNew = allowanceBefore.add(_amount); // uint256 allowanceAfter = safeApprove(_token, _spender, allowanceNew); // require(allowanceAfter == allowanceNew, "AF"); // return allowanceNew; // } // function safeDecreaseAllowance(IERC20 _token, address _spender, uint256 _amount) internal returns (uint) { // uint256 allowanceBefore = _token.allowance(address(this), _spender); // uint256 allowanceNew = allowanceBefore.sub(_amount); // uint256 allowanceAfter = safeApprove(_token, _spender, allowanceNew); // require(allowanceAfter == allowanceNew, "AF"); // return allowanceNew; // } }
Contract ABI
[{"type":"event","name":"NewAdmin","inputs":[{"type":"address","name":"oldAdmin","internalType":"address","indexed":false},{"type":"address","name":"newAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"NewPendingAdmin","inputs":[{"type":"address","name":"oldPendingAdmin","internalType":"address","indexed":false},{"type":"address","name":"newPendingAdmin","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptAdmin","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"admin","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"sellAmount","internalType":"uint256"}],"name":"buy","inputs":[{"type":"address","name":"buyToken","internalType":"address"},{"type":"address","name":"sellToken","internalType":"address"},{"type":"uint24","name":"buyTax","internalType":"uint24"},{"type":"uint24","name":"sellTax","internalType":"uint24"},{"type":"uint256","name":"buyAmount","internalType":"uint256"},{"type":"uint256","name":"maxSellAmount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"buyAmount","internalType":"uint256"}],"name":"calBuyAmount","inputs":[{"type":"address","name":"buyToken","internalType":"address"},{"type":"address","name":"sellToken","internalType":"address"},{"type":"uint24","name":"buyTax","internalType":"uint24"},{"type":"uint24","name":"sellTax","internalType":"uint24"},{"type":"uint256","name":"sellAmount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"sellAmount","internalType":"uint256"}],"name":"calSellAmount","inputs":[{"type":"address","name":"buyToken","internalType":"address"},{"type":"address","name":"sellToken","internalType":"address"},{"type":"uint24","name":"buyTax","internalType":"uint24"},{"type":"uint24","name":"sellTax","internalType":"uint24"},{"type":"uint256","name":"buyAmount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"developer","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"factory","internalType":"contract IUniswapV2Factory"},{"type":"uint16","name":"fees","internalType":"uint16"}],"name":"dexInfo","inputs":[{"type":"uint8","name":"","internalType":"uint8"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"getAvgPrice","inputs":[{"type":"address","name":"desToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"uint32","name":"secondsAgo","internalType":"uint32"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint8","name":"decimals","internalType":"uint8"}],"name":"getPrice","inputs":[{"type":"address","name":"desToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"cAvgPrice","internalType":"uint256"},{"type":"uint256","name":"hAvgPrice","internalType":"uint256"},{"type":"uint8","name":"decimals","internalType":"uint8"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"getPriceCAvgPriceHAvgPrice","inputs":[{"type":"address","name":"desToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"uint32","name":"secondsAgo","internalType":"uint32"},{"type":"bytes","name":"dexData","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"implementation","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_mojitoFactory","internalType":"contract IUniswapV2Factory"},{"type":"address","name":"_unusedFactory","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUniswapV2Factory"}],"name":"mojitoFactory","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"openLev","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"pendingAdmin","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"buyAmount","internalType":"uint256"}],"name":"sell","inputs":[{"type":"address","name":"buyToken","internalType":"address"},{"type":"address","name":"sellToken","internalType":"address"},{"type":"uint256","name":"sellAmount","internalType":"uint256"},{"type":"uint256","name":"minBuyAmount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"buyAmount","internalType":"uint256"}],"name":"sellMul","inputs":[{"type":"uint256","name":"sellAmount","internalType":"uint256"},{"type":"uint256","name":"minBuyAmount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDexInfo","inputs":[{"type":"uint8[]","name":"dexName","internalType":"uint8[]"},{"type":"address[]","name":"factoryAddr","internalType":"contract IUniswapV2Factory[]"},{"type":"uint16[]","name":"fees","internalType":"uint16[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOpenLev","inputs":[{"type":"address","name":"_openLev","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPendingAdmin","inputs":[{"type":"address","name":"newPendingAdmin","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"blockTimestampLast","internalType":"uint32"},{"type":"uint256","name":"price0","internalType":"uint256"},{"type":"uint256","name":"price1","internalType":"uint256"},{"type":"uint256","name":"price0CumulativeLast","internalType":"uint256"},{"type":"uint256","name":"price1CumulativeLast","internalType":"uint256"}],"name":"uniV2PriceOracle","inputs":[{"type":"address","name":"","internalType":"contract IUniswapV2Pair"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"updatePriceOracle","inputs":[{"type":"address","name":"desToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"uint32","name":"timeWindow","internalType":"uint32"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"pure","outputs":[],"name":"updateV3Observation","inputs":[{"type":"address","name":"desToken","internalType":"address"},{"type":"address","name":"quoteToken","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"}]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50600380546001600160a01b031916331790556135c4806100326000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80634dd18bf5116100c3578063ca4b208b1161007c578063ca4b208b146102dd578063cbf09bf8146102e5578063cf24406b146102f8578063d522a11e1461030b578063f18ef3591461031e578063f851a440146103315761014d565b80634dd18bf5146102465780635962f613146102595780635c60da1b1461026c57806396e0119714610274578063a59a36ae14610298578063a96de5bd146102bc5761014d565b806328facb231161011557806328facb23146101cf57806329a72613146101d7578063355efdd9146101df57806341da89e414610200578063485cc955146102205780634a6682bb146102335761014d565b806304e79e2914610152578063080296e4146101675780630e18b6811461019257806315426c971461019a57806326782247146101ba575b600080fd5b610165610160366004612bc0565b610339565b005b61017a610175366004612deb565b6103e0565b6040516101899392919061349b565b60405180910390f35b6101656104bb565b6101ad6101a8366004612deb565b6105bb565b604051610189919061312b565b6101c26106f9565b60405161018991906130fd565b6101c2610708565b6101c2610717565b6101f26101ed366004612bf8565b610726565b60405161018992919061348a565b61021361020e366004612d77565b610768565b604051610189919061345b565b61016561022e366004612f35565b6107cd565b610213610241366004612c58565b610886565b610165610254366004612bc0565b6108f5565b610213610267366004612c58565b6109ae565b6101c2610a07565b610287610282366004612bc0565b610a16565b6040516101899594939291906134b4565b6102ab6102a6366004612deb565b610a4d565b604051610189959493929190613464565b6102cf6102ca36600461301f565b610b10565b604051610189929190613136565b6101c2610b38565b6101656102f3366004612e5e565b610b47565b610213610306366004612ce2565b610c9a565b610213610319366004612fcb565b610d00565b61016561032c366004612bf8565b610d5f565b6101c2610d77565b6001546001600160a01b0316331461038f576040805162461bcd60e51b815260206004820152601460248201527331b0b63632b91036bab9ba1031329030b236b4b760611b604482015290519081900360640190fd5b6001600160a01b0381166103be5760405162461bcd60e51b81526004016103b59061328e565b60405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b60008060006103ee84610d86565b61040a5760405162461bcd60e51b81526004016103b590613311565b6012915060006104448888600760006104228a610da0565b60ff1681526020810191909152604001600020546001600160a01b0316610dcf565b6001600160a01b038116600090815260046020818152604092839020835160a081018552815463ffffffff1681526001820154928101929092526002810154938201939093526003830154606082015291015460808201529091506104aa898983610f68565b909a94995097509295505050505050565b6002546001600160a01b031633146105045760405162461bcd60e51b815260040180806020018281038252602281526020018061354c6022913960400191505060405180910390fd5b60018054600280546001600160a01b038082166001600160a01b031980861682179687905590921690925560408051938316808552949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600254604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a15050565b6006546000906001600160a01b031633146105e85760405162461bcd60e51b81526004016103b5906132da565b6105f182610d86565b61060d5760405162461bcd60e51b81526004016103b590613311565b600061062186866007600061042288610da0565b6001600160a01b0381166000908152600460208181526040808420815160a081018352815463ffffffff168152600182015493810193909352600281015491830191909152600381015460608301529091015460808201529192508061068a8484896012610f9f565b9150915080156106eb576001600160a01b0384166000908152600460208181526040928390208551815463ffffffff191663ffffffff9091161781559085015160018201559184015160028301556060840151600383015560808401519101555b93505050505b949350505050565b6002546001600160a01b031681565b6005546001600160a01b031681565b6006546001600160a01b031681565b6000601261075e60078361073986610da0565b60ff1681526020810191909152604001600020546001600160a01b0316868684611185565b9150935093915050565b6000336107c260078361077a86610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff16918101919091528888888886806112dc565b979650505050505050565b6001546001600160a01b031633146107f75760405162461bcd60e51b81526004016103b590613438565b50600580546001600160a01b03199081166001600160a01b0393841690811790925560408051808201909152918252601e6020808401918252600d6000526007905291517fc6af84bcd7a912c26772dce2b27a335c9acc50e9113bac42fd0b48deecc0f30c805493519390921693169290921761ffff60a01b1916600160a01b61ffff90921691909102179055565b600061089283856116ac565b92506108e9600760006108a485610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff16918101919091528888866116dc565b90506107c281866116ac565b6001546001600160a01b0316331461094b576040805162461bcd60e51b815260206004820152601460248201527331b0b63632b91036bab9ba1031329030b236b4b760611b604482015290519081900360640190fd5b600280546001600160a01b038381166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a15050565b60006107c2600760006109c085610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff169181019190915288888689896117c4565b6000546001600160a01b031681565b60046020819052600091825260409091208054600182015460028301546003840154939094015463ffffffff909216939092909185565b6000806000806000610a5e86610d86565b610a7a5760405162461bcd60e51b81526004016103b590613311565b601291506000610a928a8a600760006104228c610da0565b6001600160a01b038116600090815260046020818152604092839020835160a081018552815463ffffffff168152600182015492810192909252600281015493820193909352600383015460608201529101546080820152909150610afa82828d8d886118d2565b929e919d509b5094995097509295505050505050565b6007602052600090815260409020546001600160a01b03811690600160a01b900461ffff1682565b6003546001600160a01b031681565b6001546001600160a01b03163314610b9d576040805162461bcd60e51b815260206004820152601460248201527331b0b63632b91036bab9ba1031329030b236b4b760611b604482015290519081900360640190fd5b81518351148015610baf575080518351145b610bcb5760405162461bcd60e51b81526004016103b590613181565b60005b8351811015610c94576040518060400160405280848381518110610bee57fe5b60200260200101516001600160a01b03168152602001838381518110610c1057fe5b602002602001015161ffff1681525060076000868481518110610c2f57fe5b60209081029190910181015160ff1682528181019290925260400160002082518154939092015161ffff16600160a01b0261ffff60a01b196001600160a01b039093166001600160a01b03199094169390931791909116919091179055600101610bce565b50505050565b6000610cf460076000610cac85610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff1691810191909152898987878b8b611b09565b98975050505050505050565b60006106f160076000610d1285610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff16918101919091528585610d5a86611ee2565b611fc3565b60405162461bcd60e51b81526004016103b590613371565b6001546001600160a01b031681565b60006002610d9383610da0565b60ff16141590505b919050565b6000600182511015610dc45760405162461bcd60e51b81526004016103b59061319e565b506020015160001a90565b6000806000846001600160a01b0316866001600160a01b031610610df4578486610df7565b85855b90925090507379855a03426e15ad120df77efa623af87bd54ef36001600160a01b0385161415610e7e57838282604051602001610e35929190613039565b60405160208183030381529060405280519060200120604051602001610e5c92919061305b565b6040516020818303038152906040528051906020012060001c92505050610f61565b73ae46cbbcdfba3be0f02f463ec5486ebb4e2e65ae6001600160a01b0385161415610ede57838282604051602001610eb7929190613039565b60405160208183030381529060405280519060200120604051602001610e5c9291906130ac565b60405163e6a4390560e01b81526001600160a01b0385169063e6a4390590610f0c9089908990600401613111565b60206040518083038186803b158015610f2457600080fd5b505afa158015610f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5c9190612bdc565b925050505b9392505050565b805160009063ffffffff166001600160a01b0380851690861610610f9057826040015161075e565b82602001519150935093915050565b610fa7612a0d565b600080610fb342612081565b90508486600001510163ffffffff168163ffffffff161015610fdc57856000925092505061117c565b866001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505060008660000151820390506000886001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190612fb3565b90506000896001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b1580156110ea57600080fd5b505afa1580156110fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111229190612fb3565b895190915063ffffffff161561115f57611142828a60600151858a612094565b60208a01526080890151611159908290858a612094565b60408a01525b606089019190915260808801525063ffffffff1685525083905060015b94509492505050565b600080611193858588610dcf565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156111d157600080fd5b505afa1580156111e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112099190612f6d565b506001600160701b031691506001600160701b03169150826001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561125957600080fd5b505afa15801561126d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112919190612bdc565b6001600160a01b0316876001600160a01b0316146112c8576112c3816112bd8460ff8916600a0a6120d6565b9061212f565b6106eb565b6106eb826112bd8360ff8916600a0a6120d6565b6000806112ee88888b60000151610dcf565b9050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561132b57600080fd5b505af115801561133f573d6000803e3d6000fd5b5050505061134f8785838961218e565b9550600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561138d57600080fd5b505afa1580156113a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c59190612f6d565b506001600160701b031691506001600160701b03169150886001600160a01b03168a6001600160a01b0316106114805761147b828a6001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161142591906130fd565b60206040518083038186803b15801561143d57600080fd5b505afa158015611451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114759190612fb3565b906121d1565b6114b0565b6114b0818a6001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161142591906130fd565b975060008a6001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016114e091906130fd565b60206040518083038186803b1580156114f857600080fd5b505afa15801561150c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115309190612fb3565b905061153c8c8561222e565b61ffff1660208d01526001600160a01b03808b16908c1610156115d4576115698983858f60200151612395565b60405163022c0d9f60e01b81529095506001600160a01b0385169063022c0d9f9061159d9088906000908b90600401613153565b600060405180830381600087803b1580156115b757600080fd5b505af11580156115cb573d6000803e3d6000fd5b5050505061164b565b6115e48984848f60200151612395565b60405163022c0d9f60e01b81529095506001600160a01b0385169063022c0d9f906116189060009089908b90600401613153565b600060405180830381600087803b15801561163257600080fd5b505af1158015611646573d6000803e3d6000fd5b505050505b61167b818c6001600160a01b03166370a08231896040518263ffffffff1660e01b815260040161142591906130fd565b94508785101561169d5760405162461bcd60e51b81526004016103b59061339a565b50505050979650505050505050565b6000620f42406116cb6116c48262ffffff86166121d1565b85906120d6565b816116d257fe5b0490505b92915050565b6000806116ee85858860000151610dcf565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561172c57600080fd5b505afa158015611740573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117649190612f6d565b506001600160701b031691506001600160701b03169150856001600160a01b0316876001600160a01b031610156117b4576117aa8582846117a58c8861222e565b612395565b93505050506106f1565b6117aa8583836117a58c8861222e565b6000806117d687878a60000151610dcf565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561181457600080fd5b505afa158015611828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184c9190612f6d565b506001600160701b031691506001600160701b03169150876001600160a01b0316896001600160a01b03161061189f5761189a611889888861243e565b83836118958e8861222e565b612482565b6118b8565b6118b86118ac888861243e565b82846118958e8861222e565b93506118c4848661243e565b9a9950505050505050505050565b6000806000806000866001600160a01b0316886001600160a01b031610905060008060008c6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561192f57600080fd5b505afa158015611943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119679190612f6d565b92506001600160701b031692506001600160701b031692508361199d57611998826112bd8560ff8d16600a0a6120d6565b6119b1565b6119b1836112bd8460ff8d16600a0a6120d6565b9750836119c2578b604001516119c8565b8b602001515b8c5190965063ffffffff9081169550811685106119e757859650611af9565b8b51810384611a7557611a708e6001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015611a2c57600080fd5b505afa158015611a40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a649190612fb3565b8e60800151838d612094565b611af5565b611af58e6001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611ab157600080fd5b505afa158015611ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae99190612fb3565b8e60600151838d612094565b9750505b5050505095509550955095915050565b600080611b1b88888b60000151610dcf565b9050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611b5857600080fd5b505af1158015611b6c573d6000803e3d6000fd5b50505050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611bac57600080fd5b505afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be49190612f6d565b506001600160701b031691506001600160701b0316915060008a6001600160a01b03166370a08231336040518263ffffffff1660e01b8152600401611c2991906130fd565b60206040518083038186803b158015611c4157600080fd5b505afa158015611c55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c799190612fb3565b9050611c858c8561222e565b61ffff1660208d01526001600160a01b03808b16908c161015611d6757611cbb611caf8a8961243e565b83858f60200151612482565b9450611cc7858761243e565b945087851115611ce95760405162461bcd60e51b81526004016103b5906132aa565b611cf58a33868861218e565b506001600160a01b03841663022c0d9f611d0f8b8a61243e565b6000336040518463ffffffff1660e01b8152600401611d3093929190613153565b600060405180830381600087803b158015611d4a57600080fd5b505af1158015611d5e573d6000803e3d6000fd5b50505050611e28565b611d80611d748a8961243e565b84848f60200151612482565b9450611d8c858761243e565b945087851115611dae5760405162461bcd60e51b81526004016103b5906132aa565b611dba8a33868861218e565b506001600160a01b03841663022c0d9f6000611dd68c8b61243e565b336040518463ffffffff1660e01b8152600401611df593929190613153565b600060405180830381600087803b158015611e0f57600080fd5b505af1158015611e23573d6000803e3d6000fd5b505050505b6040516370a0823160e01b81526000906001600160a01b038d16906370a0823190611e579033906004016130fd565b60206040518083038186803b158015611e6f57600080fd5b505afa158015611e83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea79190612fb3565b9050611eb381836121d1565b8a1115611ed25760405162461bcd60e51b81526004016103b59061321b565b5050505050979650505050505050565b60606000611eef83612519565b905060008160ff1660140260050190508084511015611f205760405162461bcd60e51b81526004016103b590613248565b600560ff831667ffffffffffffffff81118015611f3c57600080fd5b50604051908082528060200260200182016040528015611f66578160200160208202803683370190505b50935060005b8360ff16811015611fba57601481028201868101602001518651606082901c90889085908110611f9857fe5b6001600160a01b03909216602092830291909101909101525050600101611f6c565b50505050919050565b600060015b8251811015612060576000836001830381518110611fe257fe5b602002602001015190506000848381518110611ffa57fe5b60200260200101519050600060018651038414905060008460011461201f5730612021565b335b90506000826120305730612032565b335b90506120448b85878d600087876112dc565b96508261204f578699505b505060019093019250611fc8915050565b50828110156106f15760405162461bcd60e51b81526004016103b59061339a565b8063ffffffff81168114610d9b57600080fd5b60006120cd8363ffffffff1660706120c58560ff16600a0a6120bf898b6121d190919063ffffffff16565b906120d6565b901c9061212f565b95945050505050565b6000826120e5575060006116d6565b828202828482816120f257fe5b0414610f615760405162461bcd60e51b815260040180806020018281038252602181526020018061356e6021913960400191505060405180910390fd5b6000808211612185576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816116d257fe5b60006001600160a01b0384163014156121bc576121b56001600160a01b0386168484612548565b90506106f1565b6120cd6001600160a01b038616858585612770565b600082821115612228576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b81516000906001600160a01b03167379855a03426e15ad120df77efa623af87bd54ef314156122d7576122d0826001600160a01b031663fef462246040518163ffffffff1660e01b815260040160206040518083038186803b15801561229357600080fd5b505afa1580156122a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cb9190612fb3565b6129a2565b90506116d6565b82516001600160a01b031673ae46cbbcdfba3be0f02f463ec5486ebb4e2e65ae141561238a576122d06122cb836001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561233c57600080fd5b505afa158015612350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123749190613003565b63ffffffff16600a6120d690919063ffffffff16565b5060208201516116d6565b60008085116123b65760405162461bcd60e51b81526004016103b59061333a565b6000841180156123c65750600083115b6123e25760405162461bcd60e51b81526004016103b590613408565b60006123fe6123f761271061ffff86166121d1565b87906120d6565b9050600061240c82866120d6565b9050600061242683612420896127106120d6565b906129b3565b905080828161243157fe5b0498975050505050505050565b600080612453620f424062ffffff85166121d1565b9050600061246d60016114758461242089620f42406120d6565b905081818161247857fe5b0495945050505050565b60008085116124a35760405162461bcd60e51b81526004016103b5906133d1565b6000841180156124b35750600083115b6124cf5760405162461bcd60e51b81526004016103b590613408565b60006124e16127106120bf87896120d6565b905060006125026124f861271061ffff87166121d1565b6120bf878a6121d1565b90506107c2600182848161251257fe5b04906129b3565b600060058251101561253d5760405162461bcd60e51b81526004016103b5906131d3565b506024015160001a90565b60008115610f61576000846001600160a01b03166370a08231856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561259f57600080fd5b505afa1580156125b3573d6000803e3d6000fd5b505050506040513d60208110156125c957600080fd5b5051604080516001600160a01b038781166024830152604480830188905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825194955090891693919290918291908083835b602083106126475780518252601f199092019160209182019101612628565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146126a9576040519150601f19603f3d011682016040523d82523d6000602084013e6126ae565b606091505b5050506000856001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561270057600080fd5b505afa158015612714573d6000803e3d6000fd5b505050506040513d602081101561272a57600080fd5b50519050818111612767576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b03949350505050565b600081156106f1576000856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156127c757600080fd5b505afa1580156127db573d6000803e3d6000fd5b505050506040513d60208110156127f157600080fd5b5051604080516001600160a01b0388811660248301528781166044830152606480830188905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251949550908a1693919290918291908083835b602083106128775780518252601f199092019160209182019101612858565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146128d9576040519150601f19603f3d011682016040523d82523d6000602084013e6128de565b606091505b5050506000866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561293057600080fd5b505afa158015612944573d6000803e3d6000fd5b505050506040513d602081101561295a57600080fd5b50519050818111612998576040805162461bcd60e51b81526020600482015260036024820152622a232360e91b604482015290519081900360640190fd5b0395945050505050565b8061ffff81168114610d9b57600080fd5b600082820183811015610f61576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6040518060a00160405280600063ffffffff168152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612a52578081fd5b81356020612a67612a6283613503565b6134df565b8281528181019085830183850287018401881015612a83578586fd5b855b85811015612aaa578135612a9881613521565b84529284019290840190600101612a85565b5090979650505050505050565b600082601f830112612ac7578081fd5b81356020612ad7612a6283613503565b8281528181019085830183850287018401881015612af3578586fd5b855b85811015612aaa57813561ffff81168114612b0e578788fd5b84529284019290840190600101612af5565b600082601f830112612b30578081fd5b813567ffffffffffffffff811115612b4457fe5b612b57601f8201601f19166020016134df565b818152846020838601011115612b6b578283fd5b816020850160208301379081016020019190915292915050565b80516001600160701b0381168114610d9b57600080fd5b803562ffffff81168114610d9b57600080fd5b803560ff81168114610d9b57600080fd5b600060208284031215612bd1578081fd5b8135610f6181613521565b600060208284031215612bed578081fd5b8151610f6181613521565b600080600060608486031215612c0c578182fd5b8335612c1781613521565b92506020840135612c2781613521565b9150604084013567ffffffffffffffff811115612c42578182fd5b612c4e86828701612b20565b9150509250925092565b60008060008060008060c08789031215612c70578182fd5b8635612c7b81613521565b95506020870135612c8b81613521565b9450612c9960408801612b9c565b9350612ca760608801612b9c565b92506080870135915060a087013567ffffffffffffffff811115612cc9578182fd5b612cd589828a01612b20565b9150509295509295509295565b600080600080600080600060e0888a031215612cfc578485fd5b8735612d0781613521565b96506020880135612d1781613521565b9550612d2560408901612b9c565b9450612d3360608901612b9c565b93506080880135925060a0880135915060c088013567ffffffffffffffff811115612d5c578182fd5b612d688a828b01612b20565b91505092959891949750929550565b600080600080600060a08688031215612d8e578283fd5b8535612d9981613521565b94506020860135612da981613521565b93506040860135925060608601359150608086013567ffffffffffffffff811115612dd2578182fd5b612dde88828901612b20565b9150509295509295909350565b60008060008060808587031215612e00578182fd5b8435612e0b81613521565b93506020850135612e1b81613521565b92506040850135612e2b81613539565b9150606085013567ffffffffffffffff811115612e46578182fd5b612e5287828801612b20565b91505092959194509250565b600080600060608486031215612e72578081fd5b833567ffffffffffffffff80821115612e89578283fd5b818601915086601f830112612e9c578283fd5b81356020612eac612a6283613503565b82815281810190858301838502870184018c1015612ec8578788fd5b8796505b84871015612ef157612edd81612baf565b835260019690960195918301918301612ecc565b5097505087013592505080821115612f07578283fd5b612f1387838801612a42565b93506040860135915080821115612f28578283fd5b50612c4e86828701612ab7565b60008060408385031215612f47578182fd5b8235612f5281613521565b91506020830135612f6281613521565b809150509250929050565b600080600060608486031215612f81578081fd5b612f8a84612b85565b9250612f9860208501612b85565b91506040840151612fa881613539565b809150509250925092565b600060208284031215612fc4578081fd5b5051919050565b600080600060608486031215612fdf578081fd5b8335925060208401359150604084013567ffffffffffffffff811115612c42578182fd5b600060208284031215613014578081fd5b8151610f6181613539565b600060208284031215613030578081fd5b610f6182612baf565b6001600160601b0319606093841b811682529190921b16601482015260280190565b6001600160f81b0319815260609290921b6001600160601b031916600183015260158201527f3b58864b0ea7cc084fc3a5dc3ca7ea2fb5cedd9aac7f9fff0c3dd9a15713f1c7603582015260550190565b6001600160f81b0319815260609290921b6001600160601b031916600183015260158201527f5d71f8561d80ed979ca73d5b742278f4719baab5f0dd78b6ca91bec31f0e2dbc603582015260550190565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b901515815260200190565b6001600160a01b0392909216825261ffff16602082015260400190565b92835260208301919091526001600160a01b0316604082015260806060820181905260009082015260a00190565b60208082526003908201526222a7a960e91b604082015260600190565b6020808252818101527f446578446174613a20746f4465782077726f6e67206461746120666f726d6174604082015260600190565b60208082526028908201527f446578446174613a20746f41727261794c656e6774682077726f6e67206461746040820152671848199bdc9b585d60c21b606082015260800190565b6020808252601390820152721ddc9bdb99c8185b5bdd5b9d08189bdd59da1d606a1b604082015260600190565b60208082526026908201527f446578446174613a20746f556e695632506174682077726f6e67206461746120604082015265199bdc9b585d60d21b606082015260800190565b602080825260029082015261060f60f31b604082015260600190565b6020808252601690820152750e6cad8d840c2dadeeadce840dcdee840cadcdeeaced60531b604082015260600190565b6020808252601d908201527f4f6e6c79206f70656e4c65762063616e20757064617465207072696365000000604082015260600190565b6020808252600f908201526e0eadce6eae0e0dee4e8cac840c8caf608b1b604082015260600190565b60208082526019908201527f494e53554646494349454e545f494e5055545f414d4f554e5400000000000000604082015260600190565b6020808252600f908201526e139bdd081a5b5c1b195b595b9d1959608a1b604082015260600190565b60208082526018908201527f62757920616d6f756e74206c657373207468616e206d696e0000000000000000604082015260600190565b6020808252601a908201527f494e53554646494349454e545f4f55545055545f414d4f554e54000000000000604082015260600190565b602080825260169082015275494e53554646494349454e545f4c495155494449545960501b604082015260600190565b6020808252600990820152682737ba1030b236b4b760b91b604082015260600190565b90815260200190565b9485526020850193909352604084019190915260ff166060830152608082015260a00190565b91825260ff16602082015260400190565b92835260ff919091166020830152604082015260600190565b63ffffffff959095168552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff811182821017156134fb57fe5b604052919050565b600067ffffffffffffffff82111561351757fe5b5060209081020190565b6001600160a01b038116811461353657600080fd5b50565b63ffffffff8116811461353657600080fdfe6f6e6c792070656e64696e6741646d696e2063616e206163636570742061646d696e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220c77aed770b4322f05085f73120bec511279477640ed03fdbff6897be17e1dd4b64736f6c63430007060033
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80634dd18bf5116100c3578063ca4b208b1161007c578063ca4b208b146102dd578063cbf09bf8146102e5578063cf24406b146102f8578063d522a11e1461030b578063f18ef3591461031e578063f851a440146103315761014d565b80634dd18bf5146102465780635962f613146102595780635c60da1b1461026c57806396e0119714610274578063a59a36ae14610298578063a96de5bd146102bc5761014d565b806328facb231161011557806328facb23146101cf57806329a72613146101d7578063355efdd9146101df57806341da89e414610200578063485cc955146102205780634a6682bb146102335761014d565b806304e79e2914610152578063080296e4146101675780630e18b6811461019257806315426c971461019a57806326782247146101ba575b600080fd5b610165610160366004612bc0565b610339565b005b61017a610175366004612deb565b6103e0565b6040516101899392919061349b565b60405180910390f35b6101656104bb565b6101ad6101a8366004612deb565b6105bb565b604051610189919061312b565b6101c26106f9565b60405161018991906130fd565b6101c2610708565b6101c2610717565b6101f26101ed366004612bf8565b610726565b60405161018992919061348a565b61021361020e366004612d77565b610768565b604051610189919061345b565b61016561022e366004612f35565b6107cd565b610213610241366004612c58565b610886565b610165610254366004612bc0565b6108f5565b610213610267366004612c58565b6109ae565b6101c2610a07565b610287610282366004612bc0565b610a16565b6040516101899594939291906134b4565b6102ab6102a6366004612deb565b610a4d565b604051610189959493929190613464565b6102cf6102ca36600461301f565b610b10565b604051610189929190613136565b6101c2610b38565b6101656102f3366004612e5e565b610b47565b610213610306366004612ce2565b610c9a565b610213610319366004612fcb565b610d00565b61016561032c366004612bf8565b610d5f565b6101c2610d77565b6001546001600160a01b0316331461038f576040805162461bcd60e51b815260206004820152601460248201527331b0b63632b91036bab9ba1031329030b236b4b760611b604482015290519081900360640190fd5b6001600160a01b0381166103be5760405162461bcd60e51b81526004016103b59061328e565b60405180910390fd5b600680546001600160a01b0319166001600160a01b0392909216919091179055565b60008060006103ee84610d86565b61040a5760405162461bcd60e51b81526004016103b590613311565b6012915060006104448888600760006104228a610da0565b60ff1681526020810191909152604001600020546001600160a01b0316610dcf565b6001600160a01b038116600090815260046020818152604092839020835160a081018552815463ffffffff1681526001820154928101929092526002810154938201939093526003830154606082015291015460808201529091506104aa898983610f68565b909a94995097509295505050505050565b6002546001600160a01b031633146105045760405162461bcd60e51b815260040180806020018281038252602281526020018061354c6022913960400191505060405180910390fd5b60018054600280546001600160a01b038082166001600160a01b031980861682179687905590921690925560408051938316808552949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600254604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a15050565b6006546000906001600160a01b031633146105e85760405162461bcd60e51b81526004016103b5906132da565b6105f182610d86565b61060d5760405162461bcd60e51b81526004016103b590613311565b600061062186866007600061042288610da0565b6001600160a01b0381166000908152600460208181526040808420815160a081018352815463ffffffff168152600182015493810193909352600281015491830191909152600381015460608301529091015460808201529192508061068a8484896012610f9f565b9150915080156106eb576001600160a01b0384166000908152600460208181526040928390208551815463ffffffff191663ffffffff9091161781559085015160018201559184015160028301556060840151600383015560808401519101555b93505050505b949350505050565b6002546001600160a01b031681565b6005546001600160a01b031681565b6006546001600160a01b031681565b6000601261075e60078361073986610da0565b60ff1681526020810191909152604001600020546001600160a01b0316868684611185565b9150935093915050565b6000336107c260078361077a86610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff16918101919091528888888886806112dc565b979650505050505050565b6001546001600160a01b031633146107f75760405162461bcd60e51b81526004016103b590613438565b50600580546001600160a01b03199081166001600160a01b0393841690811790925560408051808201909152918252601e6020808401918252600d6000526007905291517fc6af84bcd7a912c26772dce2b27a335c9acc50e9113bac42fd0b48deecc0f30c805493519390921693169290921761ffff60a01b1916600160a01b61ffff90921691909102179055565b600061089283856116ac565b92506108e9600760006108a485610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff16918101919091528888866116dc565b90506107c281866116ac565b6001546001600160a01b0316331461094b576040805162461bcd60e51b815260206004820152601460248201527331b0b63632b91036bab9ba1031329030b236b4b760611b604482015290519081900360640190fd5b600280546001600160a01b038381166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a15050565b60006107c2600760006109c085610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff169181019190915288888689896117c4565b6000546001600160a01b031681565b60046020819052600091825260409091208054600182015460028301546003840154939094015463ffffffff909216939092909185565b6000806000806000610a5e86610d86565b610a7a5760405162461bcd60e51b81526004016103b590613311565b601291506000610a928a8a600760006104228c610da0565b6001600160a01b038116600090815260046020818152604092839020835160a081018552815463ffffffff168152600182015492810192909252600281015493820193909352600383015460608201529101546080820152909150610afa82828d8d886118d2565b929e919d509b5094995097509295505050505050565b6007602052600090815260409020546001600160a01b03811690600160a01b900461ffff1682565b6003546001600160a01b031681565b6001546001600160a01b03163314610b9d576040805162461bcd60e51b815260206004820152601460248201527331b0b63632b91036bab9ba1031329030b236b4b760611b604482015290519081900360640190fd5b81518351148015610baf575080518351145b610bcb5760405162461bcd60e51b81526004016103b590613181565b60005b8351811015610c94576040518060400160405280848381518110610bee57fe5b60200260200101516001600160a01b03168152602001838381518110610c1057fe5b602002602001015161ffff1681525060076000868481518110610c2f57fe5b60209081029190910181015160ff1682528181019290925260400160002082518154939092015161ffff16600160a01b0261ffff60a01b196001600160a01b039093166001600160a01b03199094169390931791909116919091179055600101610bce565b50505050565b6000610cf460076000610cac85610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff1691810191909152898987878b8b611b09565b98975050505050505050565b60006106f160076000610d1285610da0565b60ff16815260208082019290925260409081016000208151808301909252546001600160a01b0381168252600160a01b900461ffff16918101919091528585610d5a86611ee2565b611fc3565b60405162461bcd60e51b81526004016103b590613371565b6001546001600160a01b031681565b60006002610d9383610da0565b60ff16141590505b919050565b6000600182511015610dc45760405162461bcd60e51b81526004016103b59061319e565b506020015160001a90565b6000806000846001600160a01b0316866001600160a01b031610610df4578486610df7565b85855b90925090507379855a03426e15ad120df77efa623af87bd54ef36001600160a01b0385161415610e7e57838282604051602001610e35929190613039565b60405160208183030381529060405280519060200120604051602001610e5c92919061305b565b6040516020818303038152906040528051906020012060001c92505050610f61565b73ae46cbbcdfba3be0f02f463ec5486ebb4e2e65ae6001600160a01b0385161415610ede57838282604051602001610eb7929190613039565b60405160208183030381529060405280519060200120604051602001610e5c9291906130ac565b60405163e6a4390560e01b81526001600160a01b0385169063e6a4390590610f0c9089908990600401613111565b60206040518083038186803b158015610f2457600080fd5b505afa158015610f38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f5c9190612bdc565b925050505b9392505050565b805160009063ffffffff166001600160a01b0380851690861610610f9057826040015161075e565b82602001519150935093915050565b610fa7612a0d565b600080610fb342612081565b90508486600001510163ffffffff168163ffffffff161015610fdc57856000925092505061117c565b866001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561101757600080fd5b505af115801561102b573d6000803e3d6000fd5b5050505060008660000151820390506000886001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561107557600080fd5b505afa158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad9190612fb3565b90506000896001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b1580156110ea57600080fd5b505afa1580156110fe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111229190612fb3565b895190915063ffffffff161561115f57611142828a60600151858a612094565b60208a01526080890151611159908290858a612094565b60408a01525b606089019190915260808801525063ffffffff1685525083905060015b94509492505050565b600080611193858588610dcf565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b1580156111d157600080fd5b505afa1580156111e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112099190612f6d565b506001600160701b031691506001600160701b03169150826001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561125957600080fd5b505afa15801561126d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112919190612bdc565b6001600160a01b0316876001600160a01b0316146112c8576112c3816112bd8460ff8916600a0a6120d6565b9061212f565b6106eb565b6106eb826112bd8360ff8916600a0a6120d6565b6000806112ee88888b60000151610dcf565b9050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561132b57600080fd5b505af115801561133f573d6000803e3d6000fd5b5050505061134f8785838961218e565b9550600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561138d57600080fd5b505afa1580156113a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113c59190612f6d565b506001600160701b031691506001600160701b03169150886001600160a01b03168a6001600160a01b0316106114805761147b828a6001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161142591906130fd565b60206040518083038186803b15801561143d57600080fd5b505afa158015611451573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114759190612fb3565b906121d1565b6114b0565b6114b0818a6001600160a01b03166370a08231866040518263ffffffff1660e01b815260040161142591906130fd565b975060008a6001600160a01b03166370a08231876040518263ffffffff1660e01b81526004016114e091906130fd565b60206040518083038186803b1580156114f857600080fd5b505afa15801561150c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115309190612fb3565b905061153c8c8561222e565b61ffff1660208d01526001600160a01b03808b16908c1610156115d4576115698983858f60200151612395565b60405163022c0d9f60e01b81529095506001600160a01b0385169063022c0d9f9061159d9088906000908b90600401613153565b600060405180830381600087803b1580156115b757600080fd5b505af11580156115cb573d6000803e3d6000fd5b5050505061164b565b6115e48984848f60200151612395565b60405163022c0d9f60e01b81529095506001600160a01b0385169063022c0d9f906116189060009089908b90600401613153565b600060405180830381600087803b15801561163257600080fd5b505af1158015611646573d6000803e3d6000fd5b505050505b61167b818c6001600160a01b03166370a08231896040518263ffffffff1660e01b815260040161142591906130fd565b94508785101561169d5760405162461bcd60e51b81526004016103b59061339a565b50505050979650505050505050565b6000620f42406116cb6116c48262ffffff86166121d1565b85906120d6565b816116d257fe5b0490505b92915050565b6000806116ee85858860000151610dcf565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561172c57600080fd5b505afa158015611740573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117649190612f6d565b506001600160701b031691506001600160701b03169150856001600160a01b0316876001600160a01b031610156117b4576117aa8582846117a58c8861222e565b612395565b93505050506106f1565b6117aa8583836117a58c8861222e565b6000806117d687878a60000151610dcf565b9050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561181457600080fd5b505afa158015611828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061184c9190612f6d565b506001600160701b031691506001600160701b03169150876001600160a01b0316896001600160a01b03161061189f5761189a611889888861243e565b83836118958e8861222e565b612482565b6118b8565b6118b86118ac888861243e565b82846118958e8861222e565b93506118c4848661243e565b9a9950505050505050505050565b6000806000806000866001600160a01b0316886001600160a01b031610905060008060008c6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561192f57600080fd5b505afa158015611943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119679190612f6d565b92506001600160701b031692506001600160701b031692508361199d57611998826112bd8560ff8d16600a0a6120d6565b6119b1565b6119b1836112bd8460ff8d16600a0a6120d6565b9750836119c2578b604001516119c8565b8b602001515b8c5190965063ffffffff9081169550811685106119e757859650611af9565b8b51810384611a7557611a708e6001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015611a2c57600080fd5b505afa158015611a40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a649190612fb3565b8e60800151838d612094565b611af5565b611af58e6001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611ab157600080fd5b505afa158015611ac5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ae99190612fb3565b8e60600151838d612094565b9750505b5050505095509550955095915050565b600080611b1b88888b60000151610dcf565b9050806001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611b5857600080fd5b505af1158015611b6c573d6000803e3d6000fd5b50505050600080826001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611bac57600080fd5b505afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be49190612f6d565b506001600160701b031691506001600160701b0316915060008a6001600160a01b03166370a08231336040518263ffffffff1660e01b8152600401611c2991906130fd565b60206040518083038186803b158015611c4157600080fd5b505afa158015611c55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c799190612fb3565b9050611c858c8561222e565b61ffff1660208d01526001600160a01b03808b16908c161015611d6757611cbb611caf8a8961243e565b83858f60200151612482565b9450611cc7858761243e565b945087851115611ce95760405162461bcd60e51b81526004016103b5906132aa565b611cf58a33868861218e565b506001600160a01b03841663022c0d9f611d0f8b8a61243e565b6000336040518463ffffffff1660e01b8152600401611d3093929190613153565b600060405180830381600087803b158015611d4a57600080fd5b505af1158015611d5e573d6000803e3d6000fd5b50505050611e28565b611d80611d748a8961243e565b84848f60200151612482565b9450611d8c858761243e565b945087851115611dae5760405162461bcd60e51b81526004016103b5906132aa565b611dba8a33868861218e565b506001600160a01b03841663022c0d9f6000611dd68c8b61243e565b336040518463ffffffff1660e01b8152600401611df593929190613153565b600060405180830381600087803b158015611e0f57600080fd5b505af1158015611e23573d6000803e3d6000fd5b505050505b6040516370a0823160e01b81526000906001600160a01b038d16906370a0823190611e579033906004016130fd565b60206040518083038186803b158015611e6f57600080fd5b505afa158015611e83573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ea79190612fb3565b9050611eb381836121d1565b8a1115611ed25760405162461bcd60e51b81526004016103b59061321b565b5050505050979650505050505050565b60606000611eef83612519565b905060008160ff1660140260050190508084511015611f205760405162461bcd60e51b81526004016103b590613248565b600560ff831667ffffffffffffffff81118015611f3c57600080fd5b50604051908082528060200260200182016040528015611f66578160200160208202803683370190505b50935060005b8360ff16811015611fba57601481028201868101602001518651606082901c90889085908110611f9857fe5b6001600160a01b03909216602092830291909101909101525050600101611f6c565b50505050919050565b600060015b8251811015612060576000836001830381518110611fe257fe5b602002602001015190506000848381518110611ffa57fe5b60200260200101519050600060018651038414905060008460011461201f5730612021565b335b90506000826120305730612032565b335b90506120448b85878d600087876112dc565b96508261204f578699505b505060019093019250611fc8915050565b50828110156106f15760405162461bcd60e51b81526004016103b59061339a565b8063ffffffff81168114610d9b57600080fd5b60006120cd8363ffffffff1660706120c58560ff16600a0a6120bf898b6121d190919063ffffffff16565b906120d6565b901c9061212f565b95945050505050565b6000826120e5575060006116d6565b828202828482816120f257fe5b0414610f615760405162461bcd60e51b815260040180806020018281038252602181526020018061356e6021913960400191505060405180910390fd5b6000808211612185576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b8183816116d257fe5b60006001600160a01b0384163014156121bc576121b56001600160a01b0386168484612548565b90506106f1565b6120cd6001600160a01b038616858585612770565b600082821115612228576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b81516000906001600160a01b03167379855a03426e15ad120df77efa623af87bd54ef314156122d7576122d0826001600160a01b031663fef462246040518163ffffffff1660e01b815260040160206040518083038186803b15801561229357600080fd5b505afa1580156122a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122cb9190612fb3565b6129a2565b90506116d6565b82516001600160a01b031673ae46cbbcdfba3be0f02f463ec5486ebb4e2e65ae141561238a576122d06122cb836001600160a01b03166354cf2aeb6040518163ffffffff1660e01b815260040160206040518083038186803b15801561233c57600080fd5b505afa158015612350573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123749190613003565b63ffffffff16600a6120d690919063ffffffff16565b5060208201516116d6565b60008085116123b65760405162461bcd60e51b81526004016103b59061333a565b6000841180156123c65750600083115b6123e25760405162461bcd60e51b81526004016103b590613408565b60006123fe6123f761271061ffff86166121d1565b87906120d6565b9050600061240c82866120d6565b9050600061242683612420896127106120d6565b906129b3565b905080828161243157fe5b0498975050505050505050565b600080612453620f424062ffffff85166121d1565b9050600061246d60016114758461242089620f42406120d6565b905081818161247857fe5b0495945050505050565b60008085116124a35760405162461bcd60e51b81526004016103b5906133d1565b6000841180156124b35750600083115b6124cf5760405162461bcd60e51b81526004016103b590613408565b60006124e16127106120bf87896120d6565b905060006125026124f861271061ffff87166121d1565b6120bf878a6121d1565b90506107c2600182848161251257fe5b04906129b3565b600060058251101561253d5760405162461bcd60e51b81526004016103b5906131d3565b506024015160001a90565b60008115610f61576000846001600160a01b03166370a08231856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561259f57600080fd5b505afa1580156125b3573d6000803e3d6000fd5b505050506040513d60208110156125c957600080fd5b5051604080516001600160a01b038781166024830152604480830188905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825194955090891693919290918291908083835b602083106126475780518252601f199092019160209182019101612628565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146126a9576040519150601f19603f3d011682016040523d82523d6000602084013e6126ae565b606091505b5050506000856001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561270057600080fd5b505afa158015612714573d6000803e3d6000fd5b505050506040513d602081101561272a57600080fd5b50519050818111612767576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b03949350505050565b600081156106f1576000856001600160a01b03166370a08231856040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156127c757600080fd5b505afa1580156127db573d6000803e3d6000fd5b505050506040513d60208110156127f157600080fd5b5051604080516001600160a01b0388811660248301528781166044830152606480830188905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251949550908a1693919290918291908083835b602083106128775780518252601f199092019160209182019101612858565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146128d9576040519150601f19603f3d011682016040523d82523d6000602084013e6128de565b606091505b5050506000866001600160a01b03166370a08231866040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b15801561293057600080fd5b505afa158015612944573d6000803e3d6000fd5b505050506040513d602081101561295a57600080fd5b50519050818111612998576040805162461bcd60e51b81526020600482015260036024820152622a232360e91b604482015290519081900360640190fd5b0395945050505050565b8061ffff81168114610d9b57600080fd5b600082820183811015610f61576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6040518060a00160405280600063ffffffff168152602001600081526020016000815260200160008152602001600081525090565b600082601f830112612a52578081fd5b81356020612a67612a6283613503565b6134df565b8281528181019085830183850287018401881015612a83578586fd5b855b85811015612aaa578135612a9881613521565b84529284019290840190600101612a85565b5090979650505050505050565b600082601f830112612ac7578081fd5b81356020612ad7612a6283613503565b8281528181019085830183850287018401881015612af3578586fd5b855b85811015612aaa57813561ffff81168114612b0e578788fd5b84529284019290840190600101612af5565b600082601f830112612b30578081fd5b813567ffffffffffffffff811115612b4457fe5b612b57601f8201601f19166020016134df565b818152846020838601011115612b6b578283fd5b816020850160208301379081016020019190915292915050565b80516001600160701b0381168114610d9b57600080fd5b803562ffffff81168114610d9b57600080fd5b803560ff81168114610d9b57600080fd5b600060208284031215612bd1578081fd5b8135610f6181613521565b600060208284031215612bed578081fd5b8151610f6181613521565b600080600060608486031215612c0c578182fd5b8335612c1781613521565b92506020840135612c2781613521565b9150604084013567ffffffffffffffff811115612c42578182fd5b612c4e86828701612b20565b9150509250925092565b60008060008060008060c08789031215612c70578182fd5b8635612c7b81613521565b95506020870135612c8b81613521565b9450612c9960408801612b9c565b9350612ca760608801612b9c565b92506080870135915060a087013567ffffffffffffffff811115612cc9578182fd5b612cd589828a01612b20565b9150509295509295509295565b600080600080600080600060e0888a031215612cfc578485fd5b8735612d0781613521565b96506020880135612d1781613521565b9550612d2560408901612b9c565b9450612d3360608901612b9c565b93506080880135925060a0880135915060c088013567ffffffffffffffff811115612d5c578182fd5b612d688a828b01612b20565b91505092959891949750929550565b600080600080600060a08688031215612d8e578283fd5b8535612d9981613521565b94506020860135612da981613521565b93506040860135925060608601359150608086013567ffffffffffffffff811115612dd2578182fd5b612dde88828901612b20565b9150509295509295909350565b60008060008060808587031215612e00578182fd5b8435612e0b81613521565b93506020850135612e1b81613521565b92506040850135612e2b81613539565b9150606085013567ffffffffffffffff811115612e46578182fd5b612e5287828801612b20565b91505092959194509250565b600080600060608486031215612e72578081fd5b833567ffffffffffffffff80821115612e89578283fd5b818601915086601f830112612e9c578283fd5b81356020612eac612a6283613503565b82815281810190858301838502870184018c1015612ec8578788fd5b8796505b84871015612ef157612edd81612baf565b835260019690960195918301918301612ecc565b5097505087013592505080821115612f07578283fd5b612f1387838801612a42565b93506040860135915080821115612f28578283fd5b50612c4e86828701612ab7565b60008060408385031215612f47578182fd5b8235612f5281613521565b91506020830135612f6281613521565b809150509250929050565b600080600060608486031215612f81578081fd5b612f8a84612b85565b9250612f9860208501612b85565b91506040840151612fa881613539565b809150509250925092565b600060208284031215612fc4578081fd5b5051919050565b600080600060608486031215612fdf578081fd5b8335925060208401359150604084013567ffffffffffffffff811115612c42578182fd5b600060208284031215613014578081fd5b8151610f6181613539565b600060208284031215613030578081fd5b610f6182612baf565b6001600160601b0319606093841b811682529190921b16601482015260280190565b6001600160f81b0319815260609290921b6001600160601b031916600183015260158201527f3b58864b0ea7cc084fc3a5dc3ca7ea2fb5cedd9aac7f9fff0c3dd9a15713f1c7603582015260550190565b6001600160f81b0319815260609290921b6001600160601b031916600183015260158201527f5d71f8561d80ed979ca73d5b742278f4719baab5f0dd78b6ca91bec31f0e2dbc603582015260550190565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b901515815260200190565b6001600160a01b0392909216825261ffff16602082015260400190565b92835260208301919091526001600160a01b0316604082015260806060820181905260009082015260a00190565b60208082526003908201526222a7a960e91b604082015260600190565b6020808252818101527f446578446174613a20746f4465782077726f6e67206461746120666f726d6174604082015260600190565b60208082526028908201527f446578446174613a20746f41727261794c656e6774682077726f6e67206461746040820152671848199bdc9b585d60c21b606082015260800190565b6020808252601390820152721ddc9bdb99c8185b5bdd5b9d08189bdd59da1d606a1b604082015260600190565b60208082526026908201527f446578446174613a20746f556e695632506174682077726f6e67206461746120604082015265199bdc9b585d60d21b606082015260800190565b602080825260029082015261060f60f31b604082015260600190565b6020808252601690820152750e6cad8d840c2dadeeadce840dcdee840cadcdeeaced60531b604082015260600190565b6020808252601d908201527f4f6e6c79206f70656e4c65762063616e20757064617465207072696365000000604082015260600190565b6020808252600f908201526e0eadce6eae0e0dee4e8cac840c8caf608b1b604082015260600190565b60208082526019908201527f494e53554646494349454e545f494e5055545f414d4f554e5400000000000000604082015260600190565b6020808252600f908201526e139bdd081a5b5c1b195b595b9d1959608a1b604082015260600190565b60208082526018908201527f62757920616d6f756e74206c657373207468616e206d696e0000000000000000604082015260600190565b6020808252601a908201527f494e53554646494349454e545f4f55545055545f414d4f554e54000000000000604082015260600190565b602080825260169082015275494e53554646494349454e545f4c495155494449545960501b604082015260600190565b6020808252600990820152682737ba1030b236b4b760b91b604082015260600190565b90815260200190565b9485526020850193909352604084019190915260ff166060830152608082015260a00190565b91825260ff16602082015260400190565b92835260ff919091166020830152604082015260600190565b63ffffffff959095168552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff811182821017156134fb57fe5b604052919050565b600067ffffffffffffffff82111561351757fe5b5060209081020190565b6001600160a01b038116811461353657600080fd5b50565b63ffffffff8116811461353657600080fdfe6f6e6c792070656e64696e6741646d696e2063616e206163636570742061646d696e536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220c77aed770b4322f05085f73120bec511279477640ed03fdbff6897be17e1dd4b64736f6c63430007060033