Contract Address Details
contract
0x5954Daf76721a9B1aB85ea67B33CBE43eb18F7a9
- Contract Name
- GnosisProtocolRelayer
- Creator
- 0xa601ae–4e35af at 0x724c49–d726a8
- Balance
- 0 xDai ( )
- Tokens
-
Fetching tokens...
- Transactions
- 0 Transactions
- Transfers
- 0 Transfers
- Gas Used
- Fetching gas used...
- Last Balance Update
- 28331512
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- GnosisProtocolRelayer
- Optimization enabled
- true
- Compiler version
- v0.6.6+commit.6c089d02
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2021-02-16T17:34:40.387535Z
Constructor Arguments
000000000000000000000000a601aed34dda12ff760d8abb64fd4eb3664e35af00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631300000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631300000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000b666c6fa49bb0ff305ee05c7dfd3c8f3853e3b6d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a818b4f111ccac7aa31d0bcc0806d64f2e0737d7
Arg [0] (address) : <a href=/xdai/mainnet/address/0xa601aed34dda12ff760d8abb64fd4eb3664e35af>0xa601aed34dda12ff760d8abb64fd4eb3664e35af</a>
Arg [1] (address) : <a href=/xdai/mainnet/address/0x25b06305cc4ec6afcf3e7c0b673da1ef8ae26313>0x25b06305cc4ec6afcf3e7c0b673da1ef8ae26313</a>
Arg [2] (address) : <a href=/xdai/mainnet/address/0x25b06305cc4ec6afcf3e7c0b673da1ef8ae26313>0x25b06305cc4ec6afcf3e7c0b673da1ef8ae26313</a>
Arg [3] (address[]) : [<a href=/xdai/mainnet/address/0xa818b4f111ccac7aa31d0bcc0806d64f2e0737d7>0xa818b4f111ccac7aa31d0bcc0806d64f2e0737d7</a>]
Arg [4] (address) : <a href=/xdai/mainnet/address/0xe91d153e0b41518a2ce8dd3d7944fa863463a97d>0xe91d153e0b41518a2ce8dd3d7944fa863463a97d</a>
Arg [5] (address) : <a href=/xdai/mainnet/address/0xb666c6fa49bb0ff305ee05c7dfd3c8f3853e3b6d>0xb666c6fa49bb0ff305ee05c7dfd3c8f3853e3b6d</a>
Contract source code
// File: contracts/libraries/TransferHelper.sol pragma solidity >=0.6.0; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove( address token, address to, uint256 value ) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper: APPROVE_FAILED"); } function safeTransfer( address token, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper: TRANSFER_FAILED"); } function safeTransferFrom( address token, address from, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), "TransferHelper: TRANSFER_FROM_FAILED"); } function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, "TransferHelper: ETH_TRANSFER_FAILED"); } } // File: contracts/libraries/SafeMath.sol pragma solidity =0.6.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } } // File: dxswap-core/contracts/interfaces/IDXswapPair.sol pragma solidity >=0.5.0; interface IDXswapPair { 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 swapFee() external view returns (uint32); 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; function setSwapFee(uint32) external; } // File: contracts/libraries/DXswapLibrary.sol pragma solidity >=0.5.0; library DXswapLibrary { using SafeMath for uint256; // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "DXswapLibrary: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "DXswapLibrary: ZERO_ADDRESS"); } // calculates the CREATE2 address for a pair without making any external calls function pairFor( address factory, address tokenA, address tokenB ) internal pure returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( uint256( keccak256( abi.encodePacked( hex"ff", factory, keccak256(abi.encodePacked(token0, token1)), hex"2db943b381c6ef706828ea5e89f480bd449d4d3a2b98e6da97b30d0eb41fb6d6" // init code hash ) ) ) ); } // fetches and sorts the reserves for a pair function getReserves( address factory, address tokenA, address tokenB ) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = IDXswapPair(pairFor(factory, tokenA, tokenB)).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // fetches and sorts the reserves for a pair function getSwapFee( address factory, address tokenA, address tokenB ) internal view returns (uint256 swapFee) { (address token0, ) = sortTokens(tokenA, tokenB); swapFee = IDXswapPair(pairFor(factory, tokenA, tokenB)).swapFee(); } // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) internal pure returns (uint256 amountB) { require(amountA > 0, "DXswapLibrary: INSUFFICIENT_AMOUNT"); require(reserveA > 0 && reserveB > 0, "DXswapLibrary: INSUFFICIENT_LIQUIDITY"); amountB = amountA.mul(reserveB) / reserveA; } // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut, uint256 swapFee ) internal pure returns (uint256 amountOut) { require(amountIn > 0, "DXswapLibrary: INSUFFICIENT_INPUT_AMOUNT"); require(reserveIn > 0 && reserveOut > 0, "DXswapLibrary: INSUFFICIENT_LIQUIDITY"); uint256 amountInWithFee = amountIn.mul(uint256(10000).sub(swapFee)); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(10000).add(amountInWithFee); amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut, uint256 swapFee ) internal pure returns (uint256 amountIn) { require(amountOut > 0, "DXswapLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); require(reserveIn > 0 && reserveOut > 0, "DXswapLibrary: INSUFFICIENT_LIQUIDITY"); uint256 numerator = reserveIn.mul(amountOut).mul(10000); uint256 denominator = reserveOut.sub(amountOut).mul(uint256(10000).sub(swapFee)); amountIn = (numerator / denominator).add(1); } // performs chained getAmountOut calculations on any number of pairs function getAmountsOut( address factory, uint256 amountIn, address[] memory path ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "DXswapLibrary: INVALID_PATH"); amounts = new uint256[](path.length); amounts[0] = amountIn; for (uint256 i; i < path.length - 1; i++) { (uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i], path[i + 1]); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut, getSwapFee(factory, path[i], path[i + 1])); } } // performs chained getAmountIn calculations on any number of pairs function getAmountsIn( address factory, uint256 amountOut, address[] memory path ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "DXswapLibrary: INVALID_PATH"); amounts = new uint256[](path.length); amounts[amounts.length - 1] = amountOut; for (uint256 i = path.length - 1; i > 0; i--) { (uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut, getSwapFee(factory, path[i - 1], path[i])); } } } // File: contracts/interfaces/IDXswapFactory.sol pragma solidity >=0.5.0; interface IDXswapFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint256); function INIT_CODE_PAIR_HASH() external pure returns (bytes32); function feeTo() external view returns (address); function protocolFeeDenominator() external view returns (uint8); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; function setProtocolFee(uint8 _protocolFee) external; function setSwapFee(address pair, uint32 swapFee) external; } // File: contracts/interfaces/IERC20.sol pragma solidity >=0.5.0; interface IERC20 { event Approval(address indexed owner, address indexed spender, uint256 value); event Transfer(address indexed from, address indexed to, uint256 value); function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 value) external returns (bool); function transfer(address to, uint256 value) external returns (bool); function transferFrom( address from, address to, uint256 value ) external returns (bool); } // File: contracts/interfaces/IWETH.sol pragma solidity >=0.5.0; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; function balanceOf(address guy) external returns (uint256); function approve(address guy, uint256 wad) external returns (bool); } // File: contracts/interfaces/IBatchExchange.sol pragma solidity >=0.5.0; interface IBatchExchange { function tokenAddressToIdMap(address addr) external view returns (uint16); function tokenIdToAddressMap(uint16 id) external view returns (address); function hasToken(address addr) external view returns (bool); function placeOrder( uint16 buyToken, uint16 sellToken, uint32 validUntil, uint128 buyAmount, uint128 sellAmount ) external returns (uint256); function cancelOrders(uint16[] calldata orderIds) external; } // File: contracts/interfaces/IEpochTokenLocker.sol pragma solidity >=0.5.0; interface IEpochTokenLocker { function deposit(address token, uint256 amount) external; function withdraw(address user, address token) external; function getCurrentBatchId() external view returns (uint32); function requestWithdraw(address token, uint256 amount) external; function BATCH_TIME() external view returns (uint32); } // File: contracts/libraries/FixedPoint.sol pragma solidity >=0.5.0; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) library FixedPoint { // range: [0, 2**112 - 1] // resolution: 1 / 2**112 struct uq112x112 { uint224 _x; } // range: [0, 2**144 - 1] // resolution: 1 / 2**112 struct uq144x112 { uint256 _x; } uint8 private constant RESOLUTION = 112; // encode a uint112 as a UQ112x112 function encode(uint112 x) internal pure returns (uq112x112 memory) { return uq112x112(uint224(x) << RESOLUTION); } // encodes a uint144 as a UQ144x112 function encode144(uint144 x) internal pure returns (uq144x112 memory) { return uq144x112(uint256(x) << RESOLUTION); } // divide a UQ112x112 by a uint112, returning a UQ112x112 function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) { require(x != 0, "FixedPoint: DIV_BY_ZERO"); return uq112x112(self._x / uint224(x)); } // multiply a UQ112x112 by a uint, returning a UQ144x112 // reverts on overflow function mul(uq112x112 memory self, uint256 y) internal pure returns (uq144x112 memory) { uint256 z; require(y == 0 || (z = uint256(self._x) * y) / y == uint256(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW"); return uq144x112(z); } // returns a UQ112x112 which represents the ratio of the numerator to the denominator // equivalent to encode(numerator).div(denominator) function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) { require(denominator > 0, "FixedPoint: DIV_BY_ZERO"); return uq112x112((uint224(numerator) << RESOLUTION) / denominator); } // decode a UQ112x112 into a uint112 by truncating after the radix point function decode(uq112x112 memory self) internal pure returns (uint112) { return uint112(self._x >> RESOLUTION); } // decode a UQ144x112 into a uint144 by truncating after the radix point function decode144(uq144x112 memory self) internal pure returns (uint144) { return uint144(self._x >> RESOLUTION); } } // File: contracts/libraries/DXswapOracleLibrary.sol pragma solidity >=0.5.0; // library with helper methods for oracles that are concerned with computing average prices library DXswapOracleLibrary { using FixedPoint for *; // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] function currentBlockTimestamp() internal view returns (uint32) { return uint32(block.timestamp % 2**32); } // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. function currentCumulativePrices(address pair) internal view returns ( uint256 price0Cumulative, uint256 price1Cumulative, uint32 blockTimestamp ) { blockTimestamp = currentBlockTimestamp(); price0Cumulative = IDXswapPair(pair).price0CumulativeLast(); price1Cumulative = IDXswapPair(pair).price1CumulativeLast(); // if time has elapsed since the last update on the pair, mock the accumulated price values (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IDXswapPair(pair).getReserves(); if (blockTimestampLast != blockTimestamp) { // subtraction overflow is desired uint32 timeElapsed = blockTimestamp - blockTimestampLast; // addition overflow is desired // counterfactual price0Cumulative += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; // counterfactual price1Cumulative += uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed; } } } // File: contracts/OracleCreator.sol pragma solidity =0.6.6; pragma experimental ABIEncoderV2; contract OracleCreator { using FixedPoint for *; using SafeMath for uint256; event OracleCreated( uint256 indexed _oracleIndex, address indexed _pair, uint256 _windowTime ); struct Oracle{ uint256 windowTime; address token0; address token1; IDXswapPair pair; uint32 blockTimestampLast; uint256 price0CumulativeLast; uint256 price1CumulativeLast; FixedPoint.uq112x112 price0Average; FixedPoint.uq112x112 price1Average; uint256 observationsCount; address owner; } mapping(uint256 => Oracle) public oracles; uint256 public oraclesIndex; function createOracle( uint256 windowTime, address pair ) public returns (uint256 oracleId) { IDXswapPair sourcePair = IDXswapPair(pair); address token0 = sourcePair.token0(); address token1 = sourcePair.token1(); (,, uint32 blockTimestampLast) = sourcePair.getReserves(); oracles[oraclesIndex] = Oracle({ windowTime: windowTime, token0: token0, token1: token1, pair: sourcePair, blockTimestampLast: blockTimestampLast, price0CumulativeLast: sourcePair.price0CumulativeLast(), price1CumulativeLast: sourcePair.price1CumulativeLast(), price0Average: FixedPoint.uq112x112(0), price1Average: FixedPoint.uq112x112(0), observationsCount: 0, owner: msg.sender }); oracleId = oraclesIndex; oraclesIndex++; emit OracleCreated(oracleId, address(sourcePair), windowTime); } function update(uint256 oracleIndex) public { Oracle storage oracle = oracles[oracleIndex]; require(msg.sender == oracle.owner, 'OracleCreator: CALLER_NOT_OWNER'); require(oracle.observationsCount < 2, 'OracleCreator: FINISHED_OBERSERVATION'); (uint price0Cumulative, uint price1Cumulative, uint32 blockTimestamp) = DXswapOracleLibrary.currentCumulativePrices(address(oracle.pair)); uint32 timeElapsed = blockTimestamp - oracle.blockTimestampLast; // overflow is desired // first update can be executed immediately. Ensure that at least one full period has passed since the first update require( oracle.observationsCount == 0 || timeElapsed >= oracle.windowTime, 'OracleCreator: PERIOD_NOT_ELAPSED' ); // overflow is desired, casting never truncates // cumulative price is in (uq112x112 price * seconds) units so we simply wrap it after division by time elapsed oracle.price0Average = FixedPoint.uq112x112( uint224((price0Cumulative - oracle.price0CumulativeLast) / timeElapsed) ); oracle.price1Average = FixedPoint.uq112x112( uint224((price1Cumulative - oracle.price1CumulativeLast) / timeElapsed) ); oracle.price0CumulativeLast = price0Cumulative; oracle.price1CumulativeLast = price1Cumulative; oracle.blockTimestampLast = blockTimestamp; oracle.observationsCount++; } // note this will always return 0 before update has been called successfully for the first time. function consult(uint256 oracleIndex, address token, uint256 amountIn) external view returns (uint256 amountOut) { Oracle storage oracle = oracles[oracleIndex]; FixedPoint.uq112x112 memory avg; if (token == oracle.token0) { avg = oracle.price0Average; } else { require(token == oracle.token1, 'OracleCreator: INVALID_TOKEN'); avg = oracle.price1Average; } amountOut = avg.mul(amountIn).decode144(); } function isOracleFinalized(uint256 oracleIndex) external view returns (bool){ return oracles[oracleIndex].observationsCount == 2; } function getOracleDetails(uint256 oracleIndex) external view returns (Oracle memory) { return oracles[oracleIndex]; } } // File: contracts/GnosisProtocolRelayer.sol pragma solidity =0.6.6; contract GnosisProtocolRelayer { using SafeMath for uint256; event NewOrder( uint256 indexed _orderIndex ); event PlacedTrade( uint256 indexed _orderIndex, uint256 _gpOrderID ); event WithdrawnExpiredOrder( uint256 indexed _orderIndex ); struct Order { address tokenIn; address tokenOut; uint128 tokenInAmount; uint128 tokenOutAmount; uint256 priceTolerance; uint256 minReserve; address oraclePair; uint256 startDate; uint256 deadline; uint256 oracleId; uint256 gpOrderId; address factory; bool executed; } uint256 public immutable GAS_ORACLE_UPDATE = 168364; uint256 public immutable PARTS_PER_MILLION = 1000000; uint256 public immutable BOUNTY = 0.01 ether; uint256 public immutable ORACLE_WINDOW_TIME = 120; // 2 Minutes uint32 public immutable BATCH_TIME; uint32 public immutable UINT32_MAX_VALUE = 2**32 - 1; uint128 public immutable UINT128_MAX_VALUE = 2**128 - 1; address public immutable batchExchange; address public immutable epochTokenLocker; address payable public owner; address public immutable WETH; OracleCreator public oracleCreator; uint256 public orderCount; mapping(uint256 => Order) public orders; mapping(address => bool) public exchangeFactoryWhitelist; constructor( address payable _owner, address _batchExchange, address _epochTokenLocker, address[] memory _factoryWhitelist, address _WETH, OracleCreator _oracleCreater ) public { require(_factoryWhitelist.length > 0, 'GnosisProtocolRelayer: MISSING_FACTORY_WHITELIST'); batchExchange = _batchExchange; epochTokenLocker = _epochTokenLocker; oracleCreator = _oracleCreater; owner = _owner; WETH = _WETH; BATCH_TIME = IEpochTokenLocker(_epochTokenLocker).BATCH_TIME(); for (uint i=0; i < _factoryWhitelist.length; i++) { exchangeFactoryWhitelist[_factoryWhitelist[i]] = true; } } function orderTrade( address tokenIn, address tokenOut, uint128 tokenInAmount, uint128 tokenOutAmount, uint256 priceTolerance, uint256 minReserve, uint256 startDate, uint256 deadline, address factory ) external payable returns (uint256 orderIndex) { require(exchangeFactoryWhitelist[factory], 'GnosisProtocolRelayer: INVALID_FACTORY'); require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); require(tokenIn != tokenOut, 'GnosisProtocolRelayer: INVALID_PAIR'); require(tokenInAmount > 0 && tokenOutAmount > 0, 'GnosisProtocolRelayer: INVALID_TOKEN_AMOUNT'); require(priceTolerance <= PARTS_PER_MILLION, 'GnosisProtocolRelayer: INVALID_TOLERANCE'); require(deadline <= UINT32_MAX_VALUE, 'GnosisProtocolRelayer: INVALID_DEADLINE'); require(block.timestamp <= deadline, 'GnosisProtocolRelayer: DEADLINE_REACHED'); if (tokenIn == address(0)) { require(address(this).balance >= tokenInAmount, 'GnosisProtocolRelayer: INSUFFIENT_ETH'); tokenIn = WETH; IWETH(WETH).deposit{value: tokenInAmount}(); } else if (tokenOut == address(0)) { tokenOut = WETH; } require(IERC20(tokenIn).balanceOf(address(this)) >= tokenInAmount, 'GnosisProtocolRelayer: INSUFFIENT_TOKEN_IN'); address pair = _pair(tokenIn, tokenOut, factory); require(pair != address(0), 'GnosisProtocolRelayer: UNKOWN_PAIR'); orderIndex = _OrderIndex(); orders[orderIndex] = Order({ tokenIn: tokenIn, tokenOut: tokenOut, tokenInAmount: tokenInAmount, tokenOutAmount: tokenOutAmount, priceTolerance: priceTolerance, minReserve: minReserve, oraclePair: pair, startDate: startDate, deadline: deadline, oracleId: 0, gpOrderId: 0, factory: factory, executed: false }); /* Create an oracle to calculate average price */ orders[orderIndex].oracleId = oracleCreator.createOracle(ORACLE_WINDOW_TIME, pair); emit NewOrder(orderIndex); } function placeTrade(uint256 orderIndex) external { Order storage order = orders[orderIndex]; require(orderIndex < orderCount, 'GnosisProtocolRelayer: INVALID_ORDER'); require(!order.executed, 'GnosisProtocolRelayer: ORDER_EXECUTED'); require(oracleCreator.isOracleFinalized(order.oracleId) , 'GnosisProtocolRelayer: OBSERVATION_RUNNING'); require(block.timestamp <= order.deadline, 'GnosisProtocolRelayer: DEADLINE_REACHED'); require(block.timestamp > order.startDate , 'GnosisProtocolRelayer: FUTURE_STARTDATE'); order.executed = true; /* Approve token on Gnosis Protocol */ TransferHelper.safeApprove(order.tokenIn, epochTokenLocker, order.tokenInAmount); /* Deposit token in Gnosis Protocol */ IEpochTokenLocker(epochTokenLocker).deposit(order.tokenIn, order.tokenInAmount); /* Lookup TokenIds in Gnosis Protocol */ uint16 sellToken = IBatchExchange(batchExchange).tokenAddressToIdMap(order.tokenIn); uint16 buyToken = IBatchExchange(batchExchange).tokenAddressToIdMap(order.tokenOut); uint256 expectedAmount = oracleCreator.consult( order.oracleId, order.tokenIn == address(0) ? WETH : order.tokenIn, order.tokenInAmount ); uint256 expectedAmountMin = expectedAmount.sub(expectedAmount.mul(order.priceTolerance) / PARTS_PER_MILLION); uint256 expectedTokenOutAmount = order.tokenOutAmount; require( expectedAmountMin >= expectedTokenOutAmount.sub(expectedTokenOutAmount.mul(order.priceTolerance) / PARTS_PER_MILLION), 'GnosisProtocolRelayer: INVALID_PRICE_RANGE' ); require(expectedAmountMin <= UINT128_MAX_VALUE,'GnosisProtocolRelayer: AMOUNT_OUT_OF_RANGE'); /* Calculate batch Deadline (5 Minutes window) */ uint32 validUntil = uint32(order.deadline/BATCH_TIME); uint256 gpOrderId = IBatchExchange(batchExchange).placeOrder(buyToken, sellToken, validUntil, uint128(expectedAmountMin), order.tokenInAmount); order.gpOrderId = gpOrderId; emit PlacedTrade(orderIndex, gpOrderId); } function cancelOrder(uint256 orderIndex) external { Order storage order = orders[orderIndex]; require(orderIndex < orderCount, 'GnosisProtocolRelayer: INVALID_ORDER'); require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); require(order.executed, 'GnosisProtocolRelayer: ORDER_NOT_EXECUTED'); uint16[] memory orderArray = new uint16[](1); orderArray[0] = uint16(order.gpOrderId); IBatchExchange(batchExchange).cancelOrders(orderArray); } // Updates a price oracle and sends a bounty to msg.sender function updateOracle(uint256 orderIndex) external { Order storage order = orders[orderIndex]; require(orderIndex < orderCount, 'GnosisProtocolRelayer: INVALID_ORDER'); require(block.timestamp <= order.deadline, 'GnosisProtocolRelayer: DEADLINE_REACHED'); require(!oracleCreator.isOracleFinalized(order.oracleId) , 'GnosisProtocolRelayer: OBSERVATION_ENDED'); require(block.timestamp > order.startDate, 'GnosisProtocolRelayer: FUTURE_STARTDATE'); uint256 amountBounty = GAS_ORACLE_UPDATE.mul(tx.gasprice).add(BOUNTY); (uint reserve0, uint reserve1,) = IDXswapPair(order.oraclePair).getReserves(); address token0 = IDXswapPair(order.oraclePair).token0(); address tokenIn = order.tokenIn == address(0) ? WETH : order.tokenIn; // Makes sure the reserve of TokenIn is higher then minReserve if(tokenIn == token0){ require( reserve0 >= order.minReserve, 'GnosisProtocolRelayer: RESERVE_TO_LOW' ); } else { require( reserve1 >= order.minReserve, 'GnosisProtocolRelayer: RESERVE_TO_LOW' ); } oracleCreator.update(order.oracleId); if(address(this).balance >= amountBounty){ TransferHelper.safeTransferETH(msg.sender, amountBounty); } } function withdrawExpiredOrder(uint256 orderIndex) external { Order storage order = orders[orderIndex]; require(orderIndex < orderCount, 'GnosisProtocolRelayer: INVALID_ORDER'); require(block.timestamp > order.deadline, 'GnosisProtocolRelayer: DEADLINE_NOT_REACHED'); require(!order.executed, 'GnosisProtocolRelayer: ORDER_EXECUTED'); if (order.tokenIn == WETH) { IWETH(WETH).withdraw(order.tokenInAmount); TransferHelper.safeTransferETH(owner, order.tokenInAmount); } else { TransferHelper.safeTransfer(order.tokenIn, owner, order.tokenInAmount); } order.executed = true; emit WithdrawnExpiredOrder(orderIndex); } // Requests a token withdraw on GP function requestWithdraw(address token, uint256 amount) public{ require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); IEpochTokenLocker(epochTokenLocker).requestWithdraw(token,amount); } // Releases tokens from Gnosis Protocol function withdrawToken(address token) public { require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); IEpochTokenLocker(epochTokenLocker).withdraw(address(this), token); if (token == WETH) { uint balance = IWETH(WETH).balanceOf(address(this)); IWETH(WETH).withdraw(balance); ETHWithdraw(balance); } else { uint balance = IERC20(token).balanceOf(address(this)); ERC20Withdraw(token, balance); } } // Internal function to return the pair address on a given factory function _pair(address tokenA, address tokenB, address factory) internal view returns (address pair) { require(exchangeFactoryWhitelist[factory], 'GnosisProtocolRelayer: INVALID_FACTORY'); pair = IDXswapFactory(factory).getPair(tokenA, tokenB); } // Returns an OrderIndex that is used to reference liquidity orders function _OrderIndex() internal returns(uint256 orderIndex){ orderIndex = orderCount; orderCount++; } function changeOwner(address payable _newOwner) public{ require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); owner = _newOwner; } // Allows the owner to withdraw any ERC20 from the relayer function ERC20Withdraw(address token, uint256 amount) public { require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); TransferHelper.safeTransfer(token, owner, amount); } // Allows the owner to withdraw any ETH amount from the relayer function ETHWithdraw(uint256 amount) public { require(msg.sender == owner, 'GnosisProtocolRelayer: CALLER_NOT_OWNER'); TransferHelper.safeTransferETH(owner, amount); } // Returns the data of one specific order function GetOrderDetails(uint256 orderIndex) external view returns (Order memory) { return orders[orderIndex]; } receive() external payable {} }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_owner","internalType":"address payable"},{"type":"address","name":"_batchExchange","internalType":"address"},{"type":"address","name":"_epochTokenLocker","internalType":"address"},{"type":"address[]","name":"_factoryWhitelist","internalType":"address[]"},{"type":"address","name":"_WETH","internalType":"address"},{"type":"address","name":"_oracleCreater","internalType":"contract OracleCreator"}]},{"type":"event","name":"NewOrder","inputs":[{"type":"uint256","name":"_orderIndex","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"PlacedTrade","inputs":[{"type":"uint256","name":"_orderIndex","internalType":"uint256","indexed":true},{"type":"uint256","name":"_gpOrderID","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrawnExpiredOrder","inputs":[{"type":"uint256","name":"_orderIndex","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"BATCH_TIME","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BOUNTY","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ERC20Withdraw","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"ETHWithdraw","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"GAS_ORACLE_UPDATE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct GnosisProtocolRelayer.Order","components":[{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint128","name":"tokenInAmount","internalType":"uint128"},{"type":"uint128","name":"tokenOutAmount","internalType":"uint128"},{"type":"uint256","name":"priceTolerance","internalType":"uint256"},{"type":"uint256","name":"minReserve","internalType":"uint256"},{"type":"address","name":"oraclePair","internalType":"address"},{"type":"uint256","name":"startDate","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint256","name":"oracleId","internalType":"uint256"},{"type":"uint256","name":"gpOrderId","internalType":"uint256"},{"type":"address","name":"factory","internalType":"address"},{"type":"bool","name":"executed","internalType":"bool"}]}],"name":"GetOrderDetails","inputs":[{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ORACLE_WINDOW_TIME","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PARTS_PER_MILLION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint128","name":"","internalType":"uint128"}],"name":"UINT128_MAX_VALUE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"UINT32_MAX_VALUE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"WETH","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"batchExchange","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelOrder","inputs":[{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"changeOwner","inputs":[{"type":"address","name":"_newOwner","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"epochTokenLocker","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"exchangeFactoryWhitelist","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract OracleCreator"}],"name":"oracleCreator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"orderCount","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"orderIndex","internalType":"uint256"}],"name":"orderTrade","inputs":[{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint128","name":"tokenInAmount","internalType":"uint128"},{"type":"uint128","name":"tokenOutAmount","internalType":"uint128"},{"type":"uint256","name":"priceTolerance","internalType":"uint256"},{"type":"uint256","name":"minReserve","internalType":"uint256"},{"type":"uint256","name":"startDate","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"address","name":"factory","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint128","name":"tokenInAmount","internalType":"uint128"},{"type":"uint128","name":"tokenOutAmount","internalType":"uint128"},{"type":"uint256","name":"priceTolerance","internalType":"uint256"},{"type":"uint256","name":"minReserve","internalType":"uint256"},{"type":"address","name":"oraclePair","internalType":"address"},{"type":"uint256","name":"startDate","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint256","name":"oracleId","internalType":"uint256"},{"type":"uint256","name":"gpOrderId","internalType":"uint256"},{"type":"address","name":"factory","internalType":"address"},{"type":"bool","name":"executed","internalType":"bool"}],"name":"orders","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"placeTrade","inputs":[{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"requestWithdraw","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateOracle","inputs":[{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawExpiredOrder","inputs":[{"type":"uint256","name":"orderIndex","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawToken","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
Contract Creation Code
0x6101c0604052620291ac608052620f424060a052662386f26fc1000060c052607860e0526001600160e01b0319610120526001600160801b0319610140523480156200004a57600080fd5b5060405162003532380380620035328339810160408190526200006d91620001f2565b60008351116200009a5760405162461bcd60e51b8152600401620000919062000334565b60405180910390fd5b6001600160601b0319606086811b82166101605285811b821661018052600180546001600160a01b038581166001600160a01b031992831617909255600080548b841692169190911790559084901b9091166101a0526040805163724600af60e11b815290519186169163e48c015e91600480820192602092909190829003018186803b1580156200012b57600080fd5b505afa15801562000140573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000166919062000307565b60e01b6001600160e01b0319166101005260005b8351811015620001d2576001600460008684815181106200019757fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020805460ff19169115159190911790556001016200017a565b50505050505050620003e4565b8051620001ec81620003cb565b92915050565b60008060008060008060c087890312156200020b578182fd5b86516200021881620003cb565b809650506020808801516200022d81620003cb565b60408901519096506200024081620003cb565b60608901519095506001600160401b038111156200025c578384fd5b8089018a601f8201126200026e578485fd5b80519150620002876200028183620003ab565b62000384565b82815283810190828501858502840186018e1015620002a4578788fd5b8793505b84841015620002d257620002bd8e82620001df565b835260019390930192918501918501620002a8565b508097505050505050620002ea8860808901620001df565b9150620002fb8860a08901620001df565b90509295509295509295565b60006020828403121562000319578081fd5b815163ffffffff811681146200032d578182fd5b9392505050565b60208082526030908201527f476e6f73697350726f746f636f6c52656c617965723a204d495353494e475f4660408201526f1050d513d49657d5d2125511531254d560821b606082015260800190565b6040518181016001600160401b0381118282101715620003a357600080fd5b604052919050565b60006001600160401b03821115620003c1578081fd5b5060209081020190565b6001600160a01b0381168114620003e157600080fd5b50565b60805160a05160c05160e0516101005160e01c6101205160e01c6101405160801c6101605160601c6101805160601c6101a05160601c613043620004ef6000398061059552806105e35280610a0e5280610a605280610b015280610deb5280610e0e5280610e9e528061138c528061167c5280611b965250806104cd528061072c52806109a3528061194c528061199852508061089f528061090d5280611a285280611ad25280611db35250806104a95280611d1252508061079b5280610d4e525080611d5d5280611edc52508061093152806111e25250806114cb52806117bd525080610d0e5280611c405280611cb05280611f00525080610c0952806114ef52506130436000f3fe6080604052600436106101855760003560e01c80638da5cb5b116100d1578063c58125bc1161008a578063d530f4e711610064578063d530f4e714610430578063e48c015e14610450578063ec6ea81214610465578063ffc5ea0d1461047a5761018c565b8063c58125bc146103db578063d081f2b8146103fb578063d41bee56146104105761018c565b80638da5cb5b146103255780638efcc7501461033a578063a6f9dae11461034d578063a85c38ef1461036d578063ad5c4648146103a6578063c23c1c9f146103bb5761018c565b80633e93e2011161013e57806378f753171161011857806378f75317146102c65780638570c8a9146102db57806389476069146102f05780638c0a63bf146103105761018c565b80633e93e2011461026f578063514fcac71461029157806360769551146102b15761018c565b806309656365146101915780630b34538e146101bc5780631373f170146101de5780632453ffa81461020b5780632cb2db611461022d578063397a1b281461024f5761018c565b3661018c57005b600080fd5b34801561019d57600080fd5b506101a66104a7565b6040516101b39190612f39565b60405180910390f35b3480156101c857600080fd5b506101d16104cb565b6040516101b3919061264e565b3480156101ea57600080fd5b506101fe6101f9366004612430565b6104ef565b6040516101b39190612792565b34801561021757600080fd5b50610220610504565b6040516101b39190612f8a565b34801561023957600080fd5b5061024d6102483660046125c5565b61050a565b005b34801561025b57600080fd5b5061024d61026a366004612504565b6106eb565b34801561027b57600080fd5b50610284610799565b6040516101b39190612fd2565b34801561029d57600080fd5b5061024d6102ac3660046125c5565b6107bd565b3480156102bd57600080fd5b506101d161090b565b3480156102d257600080fd5b5061022061092f565b3480156102e757600080fd5b506101d1610953565b3480156102fc57600080fd5b5061024d61030b366004612430565b610962565b34801561031c57600080fd5b50610220610c07565b34801561033157600080fd5b506101d1610c2b565b61022061034836600461246f565b610c3a565b34801561035957600080fd5b5061024d610368366004612430565b6112bc565b34801561037957600080fd5b5061038d6103883660046125c5565b611308565b6040516101b39d9c9b9a9998979695949392919061267c565b3480156103b257600080fd5b506101d161138a565b3480156103c757600080fd5b5061024d6103d63660046125c5565b6113ae565b3480156103e757600080fd5b5061024d6103f63660046125c5565b61177b565b34801561040757600080fd5b506102206117bb565b34801561041c57600080fd5b5061024d61042b3660046125c5565b6117df565b34801561043c57600080fd5b5061024d61044b366004612504565b611e98565b34801561045c57600080fd5b50610284611eda565b34801561047157600080fd5b50610220611efe565b34801561048657600080fd5b5061049a6104953660046125c5565b611f22565b6040516101b39190612e6a565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60046020526000908152604090205460ff1681565b60025481565b600081815260036020526040902060025482106105425760405162461bcd60e51b815260040161053990612d99565b60405180910390fd5b806007015442116105655760405162461bcd60e51b8152600401610539906129b2565b600a810154600160a01b900460ff16156105915760405162461bcd60e51b815260040161053990612b1d565b80547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169116141561067d576002810154604051632e1a7d4d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691632e1a7d4d91610620916001600160801b031690600401612f39565b600060405180830381600087803b15801561063a57600080fd5b505af115801561064e573d6000803e3d6000fd5b5050600054600284015461067893506001600160a01b0390911691506001600160801b0316611ff7565b6106a7565b805460005460028301546106a7926001600160a01b039081169216906001600160801b0316612089565b600a8101805460ff60a01b1916600160a01b17905560405182907f3f9d01b8340245ea975087559a7911155f1b300f5b19aa35fcc67d4adf962c8590600090a25050565b6000546001600160a01b031633146107155760405162461bcd60e51b81526004016105399061284d565b60405163072f436560e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063397a1b28906107639085908590600401612731565b600060405180830381600087803b15801561077d57600080fd5b505af1158015610791573d6000803e3d6000fd5b505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600081815260036020526040902060025482106107ec5760405162461bcd60e51b815260040161053990612d99565b6000546001600160a01b031633146108165760405162461bcd60e51b81526004016105399061284d565b600a810154600160a01b900460ff166108415760405162461bcd60e51b815260040161053990612969565b6040805160018082528183019092526060916020808301908036833701905050905081600901548160008151811061087557fe5b61ffff909216602092830291909101909101526040516312f706d360e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634bdc1b4c906108d490849060040161274a565b600060405180830381600087803b1580156108ee57600080fd5b505af1158015610902573d6000803e3d6000fd5b50505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6001546001600160a01b031681565b6000546001600160a01b0316331461098c5760405162461bcd60e51b81526004016105399061284d565b60405163f940e38560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f940e385906109da9030908590600401612662565b600060405180830381600087803b1580156109f457600080fd5b505af1158015610a08573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03161415610b77576040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190610a9590309060040161264e565b602060405180830381600087803b158015610aaf57600080fd5b505af1158015610ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae791906125dd565b604051632e1a7d4d60e01b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690632e1a7d4d90610b36908490600401612f8a565b600060405180830381600087803b158015610b5057600080fd5b505af1158015610b64573d6000803e3d6000fd5b50505050610b718161177b565b50610c04565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190610ba690309060040161264e565b60206040518083038186803b158015610bbe57600080fd5b505afa158015610bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf691906125dd565b9050610c028282611e98565b505b50565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b031681565b6001600160a01b03811660009081526004602052604081205460ff16610c725760405162461bcd60e51b815260040161053990612bf1565b6000546001600160a01b03163314610c9c5760405162461bcd60e51b81526004016105399061284d565b886001600160a01b03168a6001600160a01b03161415610cce5760405162461bcd60e51b815260040161053990612d56565b6000886001600160801b0316118015610cf057506000876001600160801b0316115b610d0c5760405162461bcd60e51b815260040161053990612cc6565b7f0000000000000000000000000000000000000000000000000000000000000000861115610d4c5760405162461bcd60e51b8152600401610539906129fd565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff16831115610d925760405162461bcd60e51b815260040161053990612c7f565b82421115610db25760405162461bcd60e51b815260040161053990612ad6565b6001600160a01b038a16610e8e57876001600160801b0316471015610de95760405162461bcd60e51b815260040161053990612d11565b7f000000000000000000000000000000000000000000000000000000000000000099507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0896001600160801b03166040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7057600080fd5b505af1158015610e84573d6000803e3d6000fd5b5050505050610ec0565b6001600160a01b038916610ec0577f000000000000000000000000000000000000000000000000000000000000000098505b6040516370a0823160e01b81526001600160801b038916906001600160a01b038c16906370a0823190610ef790309060040161264e565b60206040518083038186803b158015610f0f57600080fd5b505afa158015610f23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4791906125dd565b1015610f655760405162461bcd60e51b815260040161053990612e20565b6000610f728b8b85612177565b90506001600160a01b038116610f9a5760405162461bcd60e51b815260040161053990612927565b610fa2612235565b9150604051806101a001604052808c6001600160a01b031681526020018b6001600160a01b031681526020018a6001600160801b03168152602001896001600160801b03168152602001888152602001878152602001826001600160a01b031681526020018681526020018581526020016000815260200160008152602001846001600160a01b03168152602001600015158152506003600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160801b0302191690836001600160801b0316021790555060608201518160020160106101000a8154816001600160801b0302191690836001600160801b031602179055506080820151816003015560a0820151816004015560c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e0820151816006015561010082015181600701556101208201518160080155610140820151816009015561016082015181600a0160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061018082015181600a0160146101000a81548160ff021916908315150217905550905050600160009054906101000a90046001600160a01b03166001600160a01b03166306649d677f0000000000000000000000000000000000000000000000000000000000000000836040518363ffffffff1660e01b815260040161121f929190612f93565b602060405180830381600087803b15801561123957600080fd5b505af115801561124d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127191906125dd565b60008381526003602052604080822060080192909255905183917fd56de72b04be4cf70c2bab5e6905fb51e28beb22f7a5d40a6dc4103149d6110691a2509998505050505050505050565b6000546001600160a01b031633146112e65760405162461bcd60e51b81526004016105399061284d565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006860154600787015460088801546009890154600a909901546001600160a01b039889169a978916996001600160801b03808a169a600160801b909a04169895861695909190811690600160a01b900460ff168d565b7f000000000000000000000000000000000000000000000000000000000000000081565b600081815260036020526040902060025482106113dd5760405162461bcd60e51b815260040161053990612d99565b80600701544211156114015760405162461bcd60e51b815260040161053990612ad6565b60015460088201546040516325fa700360e01b81526001600160a01b03909216916325fa70039161143491600401612f8a565b60206040518083038186803b15801561144c57600080fd5b505afa158015611460573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611484919061252f565b156114a15760405162461bcd60e51b815260040161053990612c37565b806006015442116114c45760405162461bcd60e51b815260040161053990612a8f565b60006115267f000000000000000000000000000000000000000000000000000000000000000061151a7f00000000000000000000000000000000000000000000000000000000000000003a63ffffffff61224316565b9063ffffffff61228016565b90506000808360050160009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561157b57600080fd5b505afa15801561158f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b3919061254f565b506001600160701b031691506001600160701b0316915060008460050160009054906101000a90046001600160a01b03166001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561161c57600080fd5b505afa158015611630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116549190612453565b85549091506000906001600160a01b03161561167a5785546001600160a01b031661169c565b7f00000000000000000000000000000000000000000000000000000000000000005b9050816001600160a01b0316816001600160a01b031614156116e15785600401548410156116dc5760405162461bcd60e51b815260040161053990612b62565b611705565b85600401548310156117055760405162461bcd60e51b815260040161053990612b62565b6001546008870154604051634155c48560e11b81526001600160a01b03909216916382ab890a9161173891600401612f8a565b600060405180830381600087803b15801561175257600080fd5b505af1158015611766573d6000803e3d6000fd5b50505050844710610902576109023386611ff7565b6000546001600160a01b031633146117a55760405162461bcd60e51b81526004016105399061284d565b600054610c04906001600160a01b031682611ff7565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000818152600360205260409020600254821061180e5760405162461bcd60e51b815260040161053990612d99565b600a810154600160a01b900460ff161561183a5760405162461bcd60e51b815260040161053990612b1d565b60015460088201546040516325fa700360e01b81526001600160a01b03909216916325fa70039161186d91600401612f8a565b60206040518083038186803b15801561188557600080fd5b505afa158015611899573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118bd919061252f565b6118d95760405162461bcd60e51b815260040161053990612ba7565b80600701544211156118fd5760405162461bcd60e51b815260040161053990612ad6565b806006015442116119205760405162461bcd60e51b815260040161053990612a8f565b600a8101805460ff60a01b1916600160a01b1790558054600282015461197a916001600160a01b0316907f0000000000000000000000000000000000000000000000000000000000000000906001600160801b03166122a3565b805460028201546040516311f9fbc960e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116936347e7ef24936119db9391909216916001600160801b03169060040161270f565b600060405180830381600087803b1580156119f557600080fd5b505af1158015611a09573d6000803e3d6000fd5b5050825460405163ef574d2360e01b8152600093506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116935063ef574d2392611a609291169060040161264e565b60206040518083038186803b158015611a7857600080fd5b505afa158015611a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab091906125a3565b600183015460405163ef574d2360e01b81529192506000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169263ef574d2392611b0b92919091169060040161264e565b60206040518083038186803b158015611b2357600080fd5b505afa158015611b37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5b91906125a3565b600154600885015485549293506000926001600160a01b0392831692634023282b92911615611b945786546001600160a01b0316611bb6565b7f00000000000000000000000000000000000000000000000000000000000000005b60028801546040516001600160e01b031960e086901b168152611be79392916001600160801b031690600401612faa565b60206040518083038186803b158015611bff57600080fd5b505afa158015611c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3791906125dd565b90506000611c8c7f0000000000000000000000000000000000000000000000000000000000000000611c7687600301548561224390919063ffffffff16565b81611c7d57fe5b8491900463ffffffff61238a16565b60028601546003870154919250600160801b90046001600160801b031690611cf1907f000000000000000000000000000000000000000000000000000000000000000090611cdb908490612243565b81611ce257fe5b8391900463ffffffff61238a16565b821015611d105760405162461bcd60e51b815260040161053990612803565b7f00000000000000000000000000000000000000000000000000000000000000006001600160801b0316821115611d595760405162461bcd60e51b815260040161053990612a45565b60007f000000000000000000000000000000000000000000000000000000000000000063ffffffff16876007015481611d8e57fe5b60028901546040516309b0f4e560e21b81529290910492506000916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916326c3d39491611df8918a918c9188918b916001600160801b031690600401612f4d565b602060405180830381600087803b158015611e1257600080fd5b505af1158015611e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4a91906125dd565b9050808860090181905550887f38f1372ae30d4273e14ea8b395321dc1e4d5fcad60cd0785b0b34ef99b74f2a182604051611e859190612f8a565b60405180910390a2505050505050505050565b6000546001600160a01b03163314611ec25760405162461bcd60e51b81526004016105399061284d565b600054610c029083906001600160a01b031683612089565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b611f2a6123ad565b5060009081526003602081815260409283902083516101a08101855281546001600160a01b039081168252600183015481169382019390935260028201546001600160801b0380821696830196909652600160801b90049094166060850152918201546080840152600482015460a08401526005820154811660c0840152600682015460e0840152600782015461010084015260088201546101208401526009820154610140840152600a90910154908116610160830152600160a01b900460ff16151561018082015290565b604080516000808252602082019092526001600160a01b0384169083906040516120219190612615565b60006040518083038185875af1925050503d806000811461205e576040519150601f19603f3d011682016040523d82523d6000602084013e612063565b606091505b50509050806120845760405162461bcd60e51b815260040161053990612ddd565b505050565b60006060846001600160a01b031663a9059cbb85856040516024016120af929190612731565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516120e89190612615565b6000604051808303816000865af19150503d8060008114612125576040519150601f19603f3d011682016040523d82523d6000602084013e61212a565b606091505b5091509150818015612154575080511580612154575080806020019051810190612154919061252f565b6121705760405162461bcd60e51b8152600401610539906127cc565b5050505050565b6001600160a01b03811660009081526004602052604081205460ff166121af5760405162461bcd60e51b815260040161053990612bf1565b60405163e6a4390560e01b81526001600160a01b0383169063e6a43905906121dd9087908790600401612662565b60206040518083038186803b1580156121f557600080fd5b505afa158015612209573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222d9190612453565b949350505050565b600280546001810190915590565b600081158061225e5750508082028282828161225b57fe5b04145b61227a5760405162461bcd60e51b815260040161053990612894565b92915050565b8082018281101561227a5760405162461bcd60e51b8152600401610539906128c2565b60006060846001600160a01b031663095ea7b385856040516024016122c9929190612731565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516123029190612615565b6000604051808303816000865af19150503d806000811461233f576040519150601f19603f3d011682016040523d82523d6000602084013e612344565b606091505b509150915081801561236e57508051158061236e57508080602001905181019061236e919061252f565b6121705760405162461bcd60e51b8152600401610539906128f0565b8082038281111561227a5760405162461bcd60e51b81526004016105399061279d565b604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915290565b80356001600160801b038116811461227a57600080fd5b600060208284031215612441578081fd5b813561244c81612fe3565b9392505050565b600060208284031215612464578081fd5b815161244c81612fe3565b60008060008060008060008060006101208a8c03121561248d578485fd5b893561249881612fe3565b985060208a01356124a881612fe3565b97506124b78b60408c01612419565b96506124c68b60608c01612419565b955060808a0135945060a08a0135935060c08a0135925060e08a013591506101008a01356124f381612fe3565b809150509295985092959850929598565b60008060408385031215612516578182fd5b823561252181612fe3565b946020939093013593505050565b600060208284031215612540578081fd5b8151801515811461244c578182fd5b600080600060608486031215612563578283fd5b835161256e81612ff8565b602085015190935061257f81612ff8565b604085015190925063ffffffff81168114612598578182fd5b809150509250925092565b6000602082840312156125b4578081fd5b815161ffff8116811461244c578182fd5b6000602082840312156125d6578081fd5b5035919050565b6000602082840312156125ee578081fd5b5051919050565b6001600160a01b03169052565b15159052565b6001600160801b03169052565b60008251815b81811015612635576020818601810151858301520161261b565b818111156126435782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b038e811682528d811660208301526001600160801b038d811660408401528c166060830152608082018b905260a082018a9052881660c082015260e081018790526101008101869052610120810185905261014081018490526101a081016126ef6101608301856125f5565b6126fd610180830184612602565b9e9d5050505050505050505050505050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561278657835161ffff1683529284019291840191600101612766565b50909695505050505050565b901515815260200190565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b6020808252601f908201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604082015260600190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f50604082015269524943455f52414e474560b01b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a2043414c4c45525f4e4f6040820152662a2fa7aba722a960c91b606082015260800190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601e908201527f5472616e7366657248656c7065723a20415050524f56455f4641494c45440000604082015260600190565b60208082526022908201527f476e6f73697350726f746f636f6c52656c617965723a20554e4b4f574e5f504160408201526124a960f11b606082015260800190565b60208082526029908201527f476e6f73697350726f746f636f6c52656c617965723a204f524445525f4e4f5460408201526817d1561150d555115160ba1b606082015260800190565b6020808252602b908201527f476e6f73697350726f746f636f6c52656c617965723a20444541444c494e455f60408201526a1393d517d4915050d2115160aa1b606082015260800190565b60208082526028908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f546040820152674f4c4552414e434560c01b606082015260800190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a20414d4f554e545f4f55604082015269545f4f465f52414e474560b01b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a204655545552455f53546040820152664152544441544560c81b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a20444541444c494e455f60408201526614915050d2115160ca1b606082015260800190565b60208082526025908201527f476e6f73697350726f746f636f6c52656c617965723a204f524445525f45584560408201526410d555115160da1b606082015260800190565b60208082526025908201527f476e6f73697350726f746f636f6c52656c617965723a20524553455256455f546040820152644f5f4c4f5760d81b606082015260800190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a204f42534552564154496040820152694f4e5f52554e4e494e4760b01b606082015260800190565b60208082526026908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f466040820152654143544f525960d01b606082015260800190565b60208082526028908201527f476e6f73697350726f746f636f6c52656c617965723a204f425345525641544960408201526713d397d15391115160c21b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f446040820152664541444c494e4560c81b606082015260800190565b6020808252602b908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f5460408201526a13d2d15397d05353d5539560aa1b606082015260800190565b60208082526025908201527f476e6f73697350726f746f636f6c52656c617965723a20494e5355464649454e6040820152640a8be8aa8960db1b606082015260800190565b60208082526023908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f5060408201526220a4a960e91b606082015260800190565b60208082526024908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f4f604082015263292222a960e11b606082015260800190565b60208082526023908201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960408201526213115160ea1b606082015260800190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a20494e5355464649454e6040820152692a2faa27a5a2a72fa4a760b11b606082015260800190565b60006101a082019050612e7e8284516125f5565b6020830151612e9060208401826125f5565b506040830151612ea36040840182612608565b506060830151612eb66060840182612608565b506080830151608083015260a083015160a083015260c0830151612edd60c08401826125f5565b5060e0838101519083015261010080840151908301526101208084015190830152610140808401519083015261016080840151612f1c828501826125f5565b505061018080840151612f3182850182612602565b505092915050565b6001600160801b0391909116815260200190565b61ffff958616815293909416602084015263ffffffff9190911660408301526001600160801b039081166060830152909116608082015260a00190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9283526001600160a01b039190911660208301526001600160801b0316604082015260600190565b63ffffffff91909116815260200190565b6001600160a01b0381168114610c0457600080fd5b6001600160701b0381168114610c0457600080fdfea264697066735822122086fe92b006407da2e552996ecc99c1e742c5b4cc392a50e7aeb8dff2faed44c364736f6c63430006060033000000000000000000000000a601aed34dda12ff760d8abb64fd4eb3664e35af00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631300000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631300000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d000000000000000000000000b666c6fa49bb0ff305ee05c7dfd3c8f3853e3b6d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a818b4f111ccac7aa31d0bcc0806d64f2e0737d7
Deployed ByteCode
0x6080604052600436106101855760003560e01c80638da5cb5b116100d1578063c58125bc1161008a578063d530f4e711610064578063d530f4e714610430578063e48c015e14610450578063ec6ea81214610465578063ffc5ea0d1461047a5761018c565b8063c58125bc146103db578063d081f2b8146103fb578063d41bee56146104105761018c565b80638da5cb5b146103255780638efcc7501461033a578063a6f9dae11461034d578063a85c38ef1461036d578063ad5c4648146103a6578063c23c1c9f146103bb5761018c565b80633e93e2011161013e57806378f753171161011857806378f75317146102c65780638570c8a9146102db57806389476069146102f05780638c0a63bf146103105761018c565b80633e93e2011461026f578063514fcac71461029157806360769551146102b15761018c565b806309656365146101915780630b34538e146101bc5780631373f170146101de5780632453ffa81461020b5780632cb2db611461022d578063397a1b281461024f5761018c565b3661018c57005b600080fd5b34801561019d57600080fd5b506101a66104a7565b6040516101b39190612f39565b60405180910390f35b3480156101c857600080fd5b506101d16104cb565b6040516101b3919061264e565b3480156101ea57600080fd5b506101fe6101f9366004612430565b6104ef565b6040516101b39190612792565b34801561021757600080fd5b50610220610504565b6040516101b39190612f8a565b34801561023957600080fd5b5061024d6102483660046125c5565b61050a565b005b34801561025b57600080fd5b5061024d61026a366004612504565b6106eb565b34801561027b57600080fd5b50610284610799565b6040516101b39190612fd2565b34801561029d57600080fd5b5061024d6102ac3660046125c5565b6107bd565b3480156102bd57600080fd5b506101d161090b565b3480156102d257600080fd5b5061022061092f565b3480156102e757600080fd5b506101d1610953565b3480156102fc57600080fd5b5061024d61030b366004612430565b610962565b34801561031c57600080fd5b50610220610c07565b34801561033157600080fd5b506101d1610c2b565b61022061034836600461246f565b610c3a565b34801561035957600080fd5b5061024d610368366004612430565b6112bc565b34801561037957600080fd5b5061038d6103883660046125c5565b611308565b6040516101b39d9c9b9a9998979695949392919061267c565b3480156103b257600080fd5b506101d161138a565b3480156103c757600080fd5b5061024d6103d63660046125c5565b6113ae565b3480156103e757600080fd5b5061024d6103f63660046125c5565b61177b565b34801561040757600080fd5b506102206117bb565b34801561041c57600080fd5b5061024d61042b3660046125c5565b6117df565b34801561043c57600080fd5b5061024d61044b366004612504565b611e98565b34801561045c57600080fd5b50610284611eda565b34801561047157600080fd5b50610220611efe565b34801561048657600080fd5b5061049a6104953660046125c5565b611f22565b6040516101b39190612e6a565b7f00000000000000000000000000000000ffffffffffffffffffffffffffffffff81565b7f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631381565b60046020526000908152604090205460ff1681565b60025481565b600081815260036020526040902060025482106105425760405162461bcd60e51b815260040161053990612d99565b60405180910390fd5b806007015442116105655760405162461bcd60e51b8152600401610539906129b2565b600a810154600160a01b900460ff16156105915760405162461bcd60e51b815260040161053990612b1d565b80547f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d6001600160a01b039081169116141561067d576002810154604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d1691632e1a7d4d91610620916001600160801b031690600401612f39565b600060405180830381600087803b15801561063a57600080fd5b505af115801561064e573d6000803e3d6000fd5b5050600054600284015461067893506001600160a01b0390911691506001600160801b0316611ff7565b6106a7565b805460005460028301546106a7926001600160a01b039081169216906001600160801b0316612089565b600a8101805460ff60a01b1916600160a01b17905560405182907f3f9d01b8340245ea975087559a7911155f1b300f5b19aa35fcc67d4adf962c8590600090a25050565b6000546001600160a01b031633146107155760405162461bcd60e51b81526004016105399061284d565b60405163072f436560e31b81526001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae26313169063397a1b28906107639085908590600401612731565b600060405180830381600087803b15801561077d57600080fd5b505af1158015610791573d6000803e3d6000fd5b505050505050565b7f00000000000000000000000000000000000000000000000000000000ffffffff81565b600081815260036020526040902060025482106107ec5760405162461bcd60e51b815260040161053990612d99565b6000546001600160a01b031633146108165760405162461bcd60e51b81526004016105399061284d565b600a810154600160a01b900460ff166108415760405162461bcd60e51b815260040161053990612969565b6040805160018082528183019092526060916020808301908036833701905050905081600901548160008151811061087557fe5b61ffff909216602092830291909101909101526040516312f706d360e21b81526001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae263131690634bdc1b4c906108d490849060040161274a565b600060405180830381600087803b1580156108ee57600080fd5b505af1158015610902573d6000803e3d6000fd5b50505050505050565b7f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631381565b7f000000000000000000000000000000000000000000000000000000000000007881565b6001546001600160a01b031681565b6000546001600160a01b0316331461098c5760405162461bcd60e51b81526004016105399061284d565b60405163f940e38560e01b81526001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae26313169063f940e385906109da9030908590600401612662565b600060405180830381600087803b1580156109f457600080fd5b505af1158015610a08573d6000803e3d6000fd5b505050507f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d6001600160a01b0316816001600160a01b03161415610b77576040516370a0823160e01b81526000906001600160a01b037f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d16906370a0823190610a9590309060040161264e565b602060405180830381600087803b158015610aaf57600080fd5b505af1158015610ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ae791906125dd565b604051632e1a7d4d60e01b81529091506001600160a01b037f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d1690632e1a7d4d90610b36908490600401612f8a565b600060405180830381600087803b158015610b5057600080fd5b505af1158015610b64573d6000803e3d6000fd5b50505050610b718161177b565b50610c04565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190610ba690309060040161264e565b60206040518083038186803b158015610bbe57600080fd5b505afa158015610bd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf691906125dd565b9050610c028282611e98565b505b50565b7f00000000000000000000000000000000000000000000000000000000000291ac81565b6000546001600160a01b031681565b6001600160a01b03811660009081526004602052604081205460ff16610c725760405162461bcd60e51b815260040161053990612bf1565b6000546001600160a01b03163314610c9c5760405162461bcd60e51b81526004016105399061284d565b886001600160a01b03168a6001600160a01b03161415610cce5760405162461bcd60e51b815260040161053990612d56565b6000886001600160801b0316118015610cf057506000876001600160801b0316115b610d0c5760405162461bcd60e51b815260040161053990612cc6565b7f00000000000000000000000000000000000000000000000000000000000f4240861115610d4c5760405162461bcd60e51b8152600401610539906129fd565b7f00000000000000000000000000000000000000000000000000000000ffffffff63ffffffff16831115610d925760405162461bcd60e51b815260040161053990612c7f565b82421115610db25760405162461bcd60e51b815260040161053990612ad6565b6001600160a01b038a16610e8e57876001600160801b0316471015610de95760405162461bcd60e51b815260040161053990612d11565b7f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d99507f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d6001600160a01b031663d0e30db0896001600160801b03166040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e7057600080fd5b505af1158015610e84573d6000803e3d6000fd5b5050505050610ec0565b6001600160a01b038916610ec0577f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d98505b6040516370a0823160e01b81526001600160801b038916906001600160a01b038c16906370a0823190610ef790309060040161264e565b60206040518083038186803b158015610f0f57600080fd5b505afa158015610f23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4791906125dd565b1015610f655760405162461bcd60e51b815260040161053990612e20565b6000610f728b8b85612177565b90506001600160a01b038116610f9a5760405162461bcd60e51b815260040161053990612927565b610fa2612235565b9150604051806101a001604052808c6001600160a01b031681526020018b6001600160a01b031681526020018a6001600160801b03168152602001896001600160801b03168152602001888152602001878152602001826001600160a01b031681526020018681526020018581526020016000815260200160008152602001846001600160a01b03168152602001600015158152506003600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160801b0302191690836001600160801b0316021790555060608201518160020160106101000a8154816001600160801b0302191690836001600160801b031602179055506080820151816003015560a0820151816004015560c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e0820151816006015561010082015181600701556101208201518160080155610140820151816009015561016082015181600a0160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061018082015181600a0160146101000a81548160ff021916908315150217905550905050600160009054906101000a90046001600160a01b03166001600160a01b03166306649d677f0000000000000000000000000000000000000000000000000000000000000078836040518363ffffffff1660e01b815260040161121f929190612f93565b602060405180830381600087803b15801561123957600080fd5b505af115801561124d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127191906125dd565b60008381526003602052604080822060080192909255905183917fd56de72b04be4cf70c2bab5e6905fb51e28beb22f7a5d40a6dc4103149d6110691a2509998505050505050505050565b6000546001600160a01b031633146112e65760405162461bcd60e51b81526004016105399061284d565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b600360208190526000918252604090912080546001820154600283015493830154600484015460058501546006860154600787015460088801546009890154600a909901546001600160a01b039889169a978916996001600160801b03808a169a600160801b909a04169895861695909190811690600160a01b900460ff168d565b7f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d81565b600081815260036020526040902060025482106113dd5760405162461bcd60e51b815260040161053990612d99565b80600701544211156114015760405162461bcd60e51b815260040161053990612ad6565b60015460088201546040516325fa700360e01b81526001600160a01b03909216916325fa70039161143491600401612f8a565b60206040518083038186803b15801561144c57600080fd5b505afa158015611460573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611484919061252f565b156114a15760405162461bcd60e51b815260040161053990612c37565b806006015442116114c45760405162461bcd60e51b815260040161053990612a8f565b60006115267f000000000000000000000000000000000000000000000000002386f26fc1000061151a7f00000000000000000000000000000000000000000000000000000000000291ac3a63ffffffff61224316565b9063ffffffff61228016565b90506000808360050160009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561157b57600080fd5b505afa15801561158f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b3919061254f565b506001600160701b031691506001600160701b0316915060008460050160009054906101000a90046001600160a01b03166001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561161c57600080fd5b505afa158015611630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116549190612453565b85549091506000906001600160a01b03161561167a5785546001600160a01b031661169c565b7f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d5b9050816001600160a01b0316816001600160a01b031614156116e15785600401548410156116dc5760405162461bcd60e51b815260040161053990612b62565b611705565b85600401548310156117055760405162461bcd60e51b815260040161053990612b62565b6001546008870154604051634155c48560e11b81526001600160a01b03909216916382ab890a9161173891600401612f8a565b600060405180830381600087803b15801561175257600080fd5b505af1158015611766573d6000803e3d6000fd5b50505050844710610902576109023386611ff7565b6000546001600160a01b031633146117a55760405162461bcd60e51b81526004016105399061284d565b600054610c04906001600160a01b031682611ff7565b7f000000000000000000000000000000000000000000000000002386f26fc1000081565b6000818152600360205260409020600254821061180e5760405162461bcd60e51b815260040161053990612d99565b600a810154600160a01b900460ff161561183a5760405162461bcd60e51b815260040161053990612b1d565b60015460088201546040516325fa700360e01b81526001600160a01b03909216916325fa70039161186d91600401612f8a565b60206040518083038186803b15801561188557600080fd5b505afa158015611899573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118bd919061252f565b6118d95760405162461bcd60e51b815260040161053990612ba7565b80600701544211156118fd5760405162461bcd60e51b815260040161053990612ad6565b806006015442116119205760405162461bcd60e51b815260040161053990612a8f565b600a8101805460ff60a01b1916600160a01b1790558054600282015461197a916001600160a01b0316907f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae26313906001600160801b03166122a3565b805460028201546040516311f9fbc960e21b81526001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae263138116936347e7ef24936119db9391909216916001600160801b03169060040161270f565b600060405180830381600087803b1580156119f557600080fd5b505af1158015611a09573d6000803e3d6000fd5b5050825460405163ef574d2360e01b8152600093506001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae263138116935063ef574d2392611a609291169060040161264e565b60206040518083038186803b158015611a7857600080fd5b505afa158015611a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ab091906125a3565b600183015460405163ef574d2360e01b81529192506000916001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631381169263ef574d2392611b0b92919091169060040161264e565b60206040518083038186803b158015611b2357600080fd5b505afa158015611b37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5b91906125a3565b600154600885015485549293506000926001600160a01b0392831692634023282b92911615611b945786546001600160a01b0316611bb6565b7f000000000000000000000000e91d153e0b41518a2ce8dd3d7944fa863463a97d5b60028801546040516001600160e01b031960e086901b168152611be79392916001600160801b031690600401612faa565b60206040518083038186803b158015611bff57600080fd5b505afa158015611c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3791906125dd565b90506000611c8c7f00000000000000000000000000000000000000000000000000000000000f4240611c7687600301548561224390919063ffffffff16565b81611c7d57fe5b8491900463ffffffff61238a16565b60028601546003870154919250600160801b90046001600160801b031690611cf1907f00000000000000000000000000000000000000000000000000000000000f424090611cdb908490612243565b81611ce257fe5b8391900463ffffffff61238a16565b821015611d105760405162461bcd60e51b815260040161053990612803565b7f00000000000000000000000000000000ffffffffffffffffffffffffffffffff6001600160801b0316821115611d595760405162461bcd60e51b815260040161053990612a45565b60007f000000000000000000000000000000000000000000000000000000000000012c63ffffffff16876007015481611d8e57fe5b60028901546040516309b0f4e560e21b81529290910492506000916001600160a01b037f00000000000000000000000025b06305cc4ec6afcf3e7c0b673da1ef8ae2631316916326c3d39491611df8918a918c9188918b916001600160801b031690600401612f4d565b602060405180830381600087803b158015611e1257600080fd5b505af1158015611e26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e4a91906125dd565b9050808860090181905550887f38f1372ae30d4273e14ea8b395321dc1e4d5fcad60cd0785b0b34ef99b74f2a182604051611e859190612f8a565b60405180910390a2505050505050505050565b6000546001600160a01b03163314611ec25760405162461bcd60e51b81526004016105399061284d565b600054610c029083906001600160a01b031683612089565b7f000000000000000000000000000000000000000000000000000000000000012c81565b7f00000000000000000000000000000000000000000000000000000000000f424081565b611f2a6123ad565b5060009081526003602081815260409283902083516101a08101855281546001600160a01b039081168252600183015481169382019390935260028201546001600160801b0380821696830196909652600160801b90049094166060850152918201546080840152600482015460a08401526005820154811660c0840152600682015460e0840152600782015461010084015260088201546101208401526009820154610140840152600a90910154908116610160830152600160a01b900460ff16151561018082015290565b604080516000808252602082019092526001600160a01b0384169083906040516120219190612615565b60006040518083038185875af1925050503d806000811461205e576040519150601f19603f3d011682016040523d82523d6000602084013e612063565b606091505b50509050806120845760405162461bcd60e51b815260040161053990612ddd565b505050565b60006060846001600160a01b031663a9059cbb85856040516024016120af929190612731565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516120e89190612615565b6000604051808303816000865af19150503d8060008114612125576040519150601f19603f3d011682016040523d82523d6000602084013e61212a565b606091505b5091509150818015612154575080511580612154575080806020019051810190612154919061252f565b6121705760405162461bcd60e51b8152600401610539906127cc565b5050505050565b6001600160a01b03811660009081526004602052604081205460ff166121af5760405162461bcd60e51b815260040161053990612bf1565b60405163e6a4390560e01b81526001600160a01b0383169063e6a43905906121dd9087908790600401612662565b60206040518083038186803b1580156121f557600080fd5b505afa158015612209573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222d9190612453565b949350505050565b600280546001810190915590565b600081158061225e5750508082028282828161225b57fe5b04145b61227a5760405162461bcd60e51b815260040161053990612894565b92915050565b8082018281101561227a5760405162461bcd60e51b8152600401610539906128c2565b60006060846001600160a01b031663095ea7b385856040516024016122c9929190612731565b6040516020818303038152906040529060e01b6020820180516001600160e01b0383818316178352505050506040516123029190612615565b6000604051808303816000865af19150503d806000811461233f576040519150601f19603f3d011682016040523d82523d6000602084013e612344565b606091505b509150915081801561236e57508051158061236e57508080602001905181019061236e919061252f565b6121705760405162461bcd60e51b8152600401610539906128f0565b8082038281111561227a5760405162461bcd60e51b81526004016105399061279d565b604080516101a081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081019190915290565b80356001600160801b038116811461227a57600080fd5b600060208284031215612441578081fd5b813561244c81612fe3565b9392505050565b600060208284031215612464578081fd5b815161244c81612fe3565b60008060008060008060008060006101208a8c03121561248d578485fd5b893561249881612fe3565b985060208a01356124a881612fe3565b97506124b78b60408c01612419565b96506124c68b60608c01612419565b955060808a0135945060a08a0135935060c08a0135925060e08a013591506101008a01356124f381612fe3565b809150509295985092959850929598565b60008060408385031215612516578182fd5b823561252181612fe3565b946020939093013593505050565b600060208284031215612540578081fd5b8151801515811461244c578182fd5b600080600060608486031215612563578283fd5b835161256e81612ff8565b602085015190935061257f81612ff8565b604085015190925063ffffffff81168114612598578182fd5b809150509250925092565b6000602082840312156125b4578081fd5b815161ffff8116811461244c578182fd5b6000602082840312156125d6578081fd5b5035919050565b6000602082840312156125ee578081fd5b5051919050565b6001600160a01b03169052565b15159052565b6001600160801b03169052565b60008251815b81811015612635576020818601810151858301520161261b565b818111156126435782828501525b509190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b038e811682528d811660208301526001600160801b038d811660408401528c166060830152608082018b905260a082018a9052881660c082015260e081018790526101008101869052610120810185905261014081018490526101a081016126ef6101608301856125f5565b6126fd610180830184612602565b9e9d5050505050505050505050505050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561278657835161ffff1683529284019291840191600101612766565b50909695505050505050565b901515815260200190565b60208082526015908201527464732d6d6174682d7375622d756e646572666c6f7760581b604082015260600190565b6020808252601f908201527f5472616e7366657248656c7065723a205452414e534645525f4641494c454400604082015260600190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f50604082015269524943455f52414e474560b01b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a2043414c4c45525f4e4f6040820152662a2fa7aba722a960c91b606082015260800190565b60208082526014908201527364732d6d6174682d6d756c2d6f766572666c6f7760601b604082015260600190565b60208082526014908201527364732d6d6174682d6164642d6f766572666c6f7760601b604082015260600190565b6020808252601e908201527f5472616e7366657248656c7065723a20415050524f56455f4641494c45440000604082015260600190565b60208082526022908201527f476e6f73697350726f746f636f6c52656c617965723a20554e4b4f574e5f504160408201526124a960f11b606082015260800190565b60208082526029908201527f476e6f73697350726f746f636f6c52656c617965723a204f524445525f4e4f5460408201526817d1561150d555115160ba1b606082015260800190565b6020808252602b908201527f476e6f73697350726f746f636f6c52656c617965723a20444541444c494e455f60408201526a1393d517d4915050d2115160aa1b606082015260800190565b60208082526028908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f546040820152674f4c4552414e434560c01b606082015260800190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a20414d4f554e545f4f55604082015269545f4f465f52414e474560b01b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a204655545552455f53546040820152664152544441544560c81b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a20444541444c494e455f60408201526614915050d2115160ca1b606082015260800190565b60208082526025908201527f476e6f73697350726f746f636f6c52656c617965723a204f524445525f45584560408201526410d555115160da1b606082015260800190565b60208082526025908201527f476e6f73697350726f746f636f6c52656c617965723a20524553455256455f546040820152644f5f4c4f5760d81b606082015260800190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a204f42534552564154496040820152694f4e5f52554e4e494e4760b01b606082015260800190565b60208082526026908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f466040820152654143544f525960d01b606082015260800190565b60208082526028908201527f476e6f73697350726f746f636f6c52656c617965723a204f425345525641544960408201526713d397d15391115160c21b606082015260800190565b60208082526027908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f446040820152664541444c494e4560c81b606082015260800190565b6020808252602b908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f5460408201526a13d2d15397d05353d5539560aa1b606082015260800190565b60208082526025908201527f476e6f73697350726f746f636f6c52656c617965723a20494e5355464649454e6040820152640a8be8aa8960db1b606082015260800190565b60208082526023908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f5060408201526220a4a960e91b606082015260800190565b60208082526024908201527f476e6f73697350726f746f636f6c52656c617965723a20494e56414c49445f4f604082015263292222a960e11b606082015260800190565b60208082526023908201527f5472616e7366657248656c7065723a204554485f5452414e534645525f46414960408201526213115160ea1b606082015260800190565b6020808252602a908201527f476e6f73697350726f746f636f6c52656c617965723a20494e5355464649454e6040820152692a2faa27a5a2a72fa4a760b11b606082015260800190565b60006101a082019050612e7e8284516125f5565b6020830151612e9060208401826125f5565b506040830151612ea36040840182612608565b506060830151612eb66060840182612608565b506080830151608083015260a083015160a083015260c0830151612edd60c08401826125f5565b5060e0838101519083015261010080840151908301526101208084015190830152610140808401519083015261016080840151612f1c828501826125f5565b505061018080840151612f3182850182612602565b505092915050565b6001600160801b0391909116815260200190565b61ffff958616815293909416602084015263ffffffff9190911660408301526001600160801b039081166060830152909116608082015260a00190565b90815260200190565b9182526001600160a01b0316602082015260400190565b9283526001600160a01b039190911660208301526001600160801b0316604082015260600190565b63ffffffff91909116815260200190565b6001600160a01b0381168114610c0457600080fd5b6001600160701b0381168114610c0457600080fdfea264697066735822122086fe92b006407da2e552996ecc99c1e742c5b4cc392a50e7aeb8dff2faed44c364736f6c63430006060033