Source Code
Overview
S Balance
More Info
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
24558894 | 5 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
OutrunAMMPair
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 100000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {UQ112x112} from "../libraries/UQ112x112.sol"; import {FixedPoint128} from "../libraries/FixedPoint128.sol"; import {Initializable} from "../libraries/Initializable.sol"; import {IOutrunAMMPair} from "./interfaces/IOutrunAMMPair.sol"; import {ReentrancyGuard} from "../libraries/ReentrancyGuard.sol"; import {IOutrunAMMCallee} from "./interfaces/IOutrunAMMCallee.sol"; import {IOutrunAMMFactory} from "./interfaces/IOutrunAMMFactory.sol"; import {IOutrunAMMERC20, OutrunAMMERC20} from "./OutrunAMMERC20.sol"; contract OutrunAMMPair is IOutrunAMMPair, OutrunAMMERC20, ReentrancyGuard, Initializable { using UQ112x112 for uint224; bytes4 private constant SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)"))); uint256 public constant RATIO = 10000; uint256 public constant MINIMUM_LIQUIDITY = 1000; address public factory; address public token0; address public token1; uint256 public swapFeeRate; uint112 private reserve0; // uses single storage slot, accessible via getReserves uint112 private reserve1; // uses single storage slot, accessible via getReserves uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves uint256 public price0CumulativeLast; uint256 public price1CumulativeLast; uint256 public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event uint256 public feeGrowthX128; // accumulate maker fee per LP X128 mapping(address account => uint256) public feeGrowthRecordX128; // record the feeGrowthX128 when calc maker's append fee mapping(address account => uint256) public unClaimedFeesX128; function getPairTokens() external view override returns (address _token0, address _token1) { _token0 = token0; _token1 = token1; } function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { _reserve0 = reserve0; _reserve1 = reserve1; _blockTimestampLast = blockTimestampLast; } /** * @dev Preview unclaimed maker fee */ function previewMakerFee() external view override returns (uint256 amount0, uint256 amount1) { address msgSender = msg.sender; uint256 feeAppendX128 = balanceOf[msgSender] * (feeGrowthX128 - feeGrowthRecordX128[msgSender]); uint256 unClaimedFeeX128 = unClaimedFeesX128[msgSender]; if (feeAppendX128 > 0) unClaimedFeeX128 += feeAppendX128; if (unClaimedFeeX128 == 0) return (0, 0); uint256 rootKLast = Math.sqrt(kLast); amount0 = Math.mulDiv(unClaimedFeeX128, IERC20(token0).balanceOf(address(this)), FixedPoint128.Q128 * rootKLast); amount1 = Math.mulDiv(unClaimedFeeX128, IERC20(token1).balanceOf(address(this)), FixedPoint128.Q128 * rootKLast); } // called once by the factory at time of deployment function initialize( address _token0, address _token1, uint256 _swapFeeRate ) external initializer { require(_swapFeeRate < RATIO, FeeRateOverflow()); token0 = _token0; token1 = _token1; swapFeeRate = _swapFeeRate; factory = msg.sender; } /** * @dev Mint liquidity (LP) * @param to - address to receive LP token and calc this address's maker fee * @notice this low-level function should be called from a contract which performs important safety checks */ function mint(address to) external nonReentrant returns (uint256 liquidity) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings uint256 balance0 = IERC20(token0).balanceOf(address(this)); uint256 balance1 = IERC20(token1).balanceOf(address(this)); uint256 amount0 = balance0 - _reserve0; uint256 amount1 = balance1 - _reserve1; if (to != address(0)) _calcFeeX128(to); if (totalSupply == 0) { liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY; _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { uint256 rootKLast = Math.sqrt(kLast); liquidity = Math.min(amount0 * rootKLast / _reserve0, amount1 * rootKLast / _reserve1); } require(liquidity > 0, InsufficientLiquidityMinted()); _mint(to, liquidity); _update(balance0, balance1, _reserve0, _reserve1); kLast = uint256(reserve0) * uint256(reserve1); // reserve0 and reserve1 are up-to-date emit Mint(msg.sender, to, amount0, amount1); } /** * @dev Burn liquidity (LP) and withdraw token0 and token1 * @param to - Address to receive token and calc this address's maker fee * @notice - this low-level function should be called from a contract which performs important safety checks */ function burn(address to) external nonReentrant returns (uint256 amount0, uint256 amount1) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); address _token0 = token0; address _token1 = token1; uint256 balance0 = IERC20(_token0).balanceOf(address(this)); uint256 balance1 = IERC20(_token1).balanceOf(address(this)); uint256 liquidity = balanceOf[address(this)]; uint256 rootKLast = Math.sqrt(kLast); amount0 = liquidity * balance0 / rootKLast; // using balances ensures pro-rata distribution amount1 = liquidity * balance1 / rootKLast; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, InsufficientLiquidityBurned()); _burn(address(this), liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); _update(balance0, balance1, _reserve0, _reserve1); kLast = uint256(reserve0) * uint256(reserve1); // reserve0 and reserve1 are up-to-date emit Burn(msg.sender, amount0, amount1, to); } /** * @dev Swap token * @param amount0Out - Amount of token0 output * @param amount1Out - Amount of token0 output * @param to - Address to output * @param referrer - Address of rebate referrer * @notice - this low-level function should be called from a contract which performs important safety checks */ function swap(uint256 amount0Out, uint256 amount1Out, address to, address referrer, bytes calldata data) external nonReentrant { require(amount0Out > 0 || amount1Out > 0, InsufficientOutputAmount()); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); require(amount0Out < _reserve0 && amount1Out < _reserve1, InsufficientLiquidity()); uint256 balance0; uint256 balance1; address _token0 = token0; address _token1 = token1; { require(to != _token0 && to != _token1, InvalidTo()); if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); if (data.length > 0) IOutrunAMMCallee(to).OutrunAMMCall(msg.sender, amount0Out, amount1Out, data); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); } uint256 amount0In; uint256 amount1In; unchecked { amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; } require(amount0In > 0 || amount1In > 0, InsufficientInputAmount()); uint256 rebateFee0; uint256 rebateFee1; uint256 protocolFee0; uint256 protocolFee1; uint256 _swapFeeRate = swapFeeRate; { uint256 balance0Adjusted = balance0 * RATIO - amount0In * _swapFeeRate; uint256 balance1Adjusted = balance1 * RATIO - amount1In * _swapFeeRate; require( balance0Adjusted * balance1Adjusted >= uint256(_reserve0) * uint256(_reserve1) * RATIO ** 2, ProductKLoss() ); address feeTo = _feeTo(); (balance0, rebateFee0, protocolFee0) = _transferRebateAndProtocolFee(amount0In, balance0, _token0, referrer, feeTo); (balance1, rebateFee1, protocolFee1) = _transferRebateAndProtocolFee(amount1In, balance1, _token1, referrer, feeTo); } _update(balance0, balance1, _reserve0, _reserve1); { uint256 k = uint256(reserve0) * uint256(reserve1); // The market-making revenue from LPs that are proactively burned will be distributed to others uint256 actualSupply = totalSupply - proactivelyBurnedAmount; actualSupply = actualSupply == 0 ? 1 : actualSupply; feeGrowthX128 += (Math.sqrt(k) - Math.sqrt(kLast)) * FixedPoint128.Q128 / actualSupply; kLast = k; } emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); emit ProtocolFee(referrer, rebateFee0, rebateFee1, protocolFee0, protocolFee1); } /** * @dev Claim all the maker fee of msgSender * @notice - Claim global protocol fee simultaneously */ function claimMakerFee() external override returns (uint256 amount0, uint256 amount1) { address msgSender = msg.sender; _calcFeeX128(msgSender); uint256 feeX128 = unClaimedFeesX128[msgSender]; if (feeX128 == 0) return (0, 0); unClaimedFeesX128[msgSender] = 0; address _token0 = token0; address _token1 = token1; uint256 balance0 = IERC20(_token0).balanceOf(address(this)); uint256 balance1 = IERC20(_token1).balanceOf(address(this)); uint256 rootKLast = Math.sqrt(kLast); Math.mulDiv(feeX128, balance0, FixedPoint128.Q128 * rootKLast); amount0 = Math.mulDiv(feeX128, balance0, FixedPoint128.Q128 * rootKLast); amount1 = Math.mulDiv(feeX128, balance1, FixedPoint128.Q128 * rootKLast); require(amount0 > 0 && amount1 > 0, InsufficientMakerFeeClaimed()); _safeTransfer(_token0, msgSender, amount0); _safeTransfer(_token1, msgSender, amount1); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); _update(balance0, balance1, _reserve0, _reserve1); kLast = uint256(reserve0) * uint256(reserve1); } /** * @dev Force balances to match reserves * @param to - Address to receive excess tokens */ function skim(address to) external nonReentrant { address _token0 = token0; // gas savings address _token1 = token1; // gas savings _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)) - reserve0); _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)) - reserve1); } /** * @dev Force reserves to match balances */ function sync() external nonReentrant { _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); } function _safeTransfer(address token, address to, uint256 value) internal { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), TransferFailed()); } /** * @dev update reserves and, on the first call per block, price accumulators */ function _update(uint256 balance0, uint256 balance1, uint112 _reserve0, uint112 _reserve1) internal { require(balance0 <= type(uint112).max && balance1 <= type(uint112).max, Overflow()); uint32 blockTimestamp; uint32 timeElapsed; unchecked { blockTimestamp = uint32(block.timestamp % 2 ** 32); timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired } if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { // * never overflows, and + overflow is desired unchecked { price0CumulativeLast += uint256(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; price1CumulativeLast += uint256(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; } } reserve0 = uint112(balance0); reserve1 = uint112(balance1); blockTimestampLast = blockTimestamp; emit Sync(reserve0, reserve1); } /** * @dev Transfer rebate and protocol fee */ function _transferRebateAndProtocolFee( uint256 amountIn, uint256 balance, address token, address referrer, address feeTo ) internal returns(uint256 balanceAfter, uint256 rebateFee, uint256 protocolFee) { if (amountIn == 0 || feeTo == address(0)) { return (balance, 0, 0); } uint256 _swapFeeRate = swapFeeRate; if (referrer == address(0)) { // swapFee * 25% as protocolFee rebateFee = 0; protocolFee = amountIn * _swapFeeRate / (RATIO * 4); balanceAfter = balance - protocolFee; _safeTransfer(token, feeTo, protocolFee); } else { // swapFee * 25% * 20% as rebateFee, swapFee * 25% * 80% as protocolFee rebateFee = amountIn * _swapFeeRate / (RATIO * 20); protocolFee = amountIn * _swapFeeRate / (RATIO * 5); balanceAfter = balance - rebateFee - protocolFee; _safeTransfer(token, referrer, rebateFee); _safeTransfer(token, feeTo, protocolFee); } } /** * @dev Calculate the maker fee */ function _calcFeeX128(address to) internal { uint256 _feeGrowthX128 = feeGrowthX128; unchecked { uint256 feeAppendX128 = balanceOf[to] * (_feeGrowthX128 - feeGrowthRecordX128[to]); if (feeAppendX128 > 0) { unClaimedFeesX128[to] += feeAppendX128; } } feeGrowthRecordX128[to] = _feeGrowthX128; } function _feeTo() internal view returns (address) { return IOutrunAMMFactory(factory).feeTo(); } function _beforeTokenTransfer(address from, address to, uint256) internal override { if (from != address(0)) _calcFeeX128(from); if (to != address(0)) _calcFeeX128(to); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Muldiv operation overflow. */ error MathOverflowedMulDiv(); enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an overflow flag. */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an overflow flag. */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // 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. */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { 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. */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. return a / b; } // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (denominator <= prod1) { revert MathOverflowedMulDiv(); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; // a library for handling binary fixed point numbers // range: [0, 2**112 - 1] // resolution: 1 / 2**112 library UQ112x112 { uint224 constant Q112 = 2 ** 112; // encode a uint112 as a UQ112x112 function encode(uint112 y) internal pure returns (uint224 z) { unchecked { z = uint224(y) * Q112; // never overflows } } // divide a UQ112x112 by a uint112, returning a UQ112x112 function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { z = x / uint224(y); } }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; library FixedPoint128 { uint256 internal constant Q128 = 0x100000000000000000000000000000000; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; abstract contract Initializable { bool public initialized; error InvalidInitialization(); modifier initializer() { require(!initialized, InvalidInitialization()); initialized = true; _; } }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; interface IOutrunAMMPair { function MINIMUM_LIQUIDITY() external pure returns (uint256); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function price0CumulativeLast() external view returns (uint256); function price1CumulativeLast() external view returns (uint256); function kLast() external view returns (uint256); function feeGrowthX128() external view returns (uint256); function getPairTokens() external view returns (address _token0, address _token1); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function previewMakerFee() external view returns (uint256 amount0, uint256 amount1); function initialize(address token0, address token1, uint256 swapFeeRate) external; function mint(address to) external returns (uint256 liquidity); function burn(address to) external returns (uint256 amount0, uint256 amount1); function swap(uint256 amount0Out, uint256 amount1Out, address to, address referrer, bytes calldata data) external; function skim(address to) external; function sync() external; function claimMakerFee() external returns (uint256 amount0, uint256 amount1); error Locked(); error Overflow(); error Forbidden(); error InvalidTo(); error ProductKLoss(); error TransferFailed(); error FeeRateOverflow(); error InsufficientLiquidity(); error InsufficientInputAmount(); error InsufficientOutputAmount(); error InsufficientUnclaimedFee(); error InsufficientLiquidityMinted(); error InsufficientLiquidityBurned(); error InsufficientMakerFeeClaimed(); event Mint(address indexed sender, address indexed to, uint256 amount0, uint256 amount1); event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to); event Swap( address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to ); event ProtocolFee( address indexed referrer, uint256 rebateFee0, uint256 rebateFee1, uint256 protocolFee0, uint256 protocolFee1 ); event Sync(uint112 reserve0, uint112 reserve1); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; /** * @dev Outrun's ReentrancyGuard implementation, support transient variable. Modified from @openzeppelin implementation */ abstract contract ReentrancyGuard { bool transient locked; error ReentrancyGuardReentrantCall(); modifier nonReentrant() { require(!locked, ReentrancyGuardReentrantCall()); locked = true; _; locked = false; } }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; interface IOutrunAMMCallee { function OutrunAMMCall(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external; }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; interface IOutrunAMMFactory { function swapFeeRate() external view returns (uint256); function pairImplementation() external view returns (address); function feeTo() external view returns (address); function allPairs(uint256) external view returns (address pair); function allPairsLength() external view returns (uint256); function getPair(address tokenA, address tokenB) external view returns (address pair); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; error ZeroAddress(); error PairExists(); error IdenticalAddresses(); event PairCreated(address indexed token0, address indexed token1, address pair, uint256); }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; import {IOutrunAMMERC20} from "./interfaces/IOutrunAMMERC20.sol"; /** * @dev OutrunAMM's ERC20 implementation, modified from @solmate implementation */ abstract contract OutrunAMMERC20 is IOutrunAMMERC20 { string public constant name = "Outrun AMM"; string public constant symbol = "OUT-AMM"; uint8 public constant decimals = 18; uint256 public totalSupply; uint256 public proactivelyBurnedAmount; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; constructor() {} function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { _beforeTokenTransfer(msg.sender, to, amount); if (to == address(0)) proactivelyBurnedAmount += amount; balanceOf[msg.sender] -= amount; unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { _beforeTokenTransfer(from, to, amount); uint256 allowed = allowance[from][msg.sender]; if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; if (to == address(0)) proactivelyBurnedAmount += amount; balanceOf[from] -= amount; unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } function _mint(address to, uint256 amount) internal virtual { if (to == address(0)) proactivelyBurnedAmount += amount; totalSupply += amount; unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
//SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; interface IOutrunAMMERC20 { 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 (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, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); }
{ "remappings": [ "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "ds-test/=lib/solmate/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 100000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": true, "libraries": {} }
Contract ABI
API[{"inputs":[],"name":"FeeRateOverflow","type":"error"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[],"name":"InsufficientInputAmount","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientLiquidityBurned","type":"error"},{"inputs":[],"name":"InsufficientLiquidityMinted","type":"error"},{"inputs":[],"name":"InsufficientMakerFeeClaimed","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"InsufficientUnclaimedFee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidTo","type":"error"},{"inputs":[],"name":"Locked","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"Overflow","type":"error"},{"inputs":[],"name":"ProductKLoss","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"uint256","name":"rebateFee0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rebateFee1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee1","type":"uint256"}],"name":"ProtocolFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint112","name":"reserve0","type":"uint112"},{"indexed":false,"internalType":"uint112","name":"reserve1","type":"uint112"}],"name":"Sync","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATIO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimMakerFee","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"feeGrowthRecordX128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeGrowthX128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPairTokens","outputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"},{"internalType":"uint256","name":"_swapFeeRate","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"previewMakerFee","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price0CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price1CumulativeLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proactivelyBurnedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sync","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unClaimedFeesX128","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6080806040523460155761305a908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f5f3560e01c806306fdde03146122665780630902f1ac146121d6578063095ea7b3146121335780630dfe1681146120e2578063158ef93e146120a25780631794bb3c14611f7557806318160ddd14611f3b57806322a6984014611ed857806323b872dd14611da95780632f1f0c4e14611d71578063313ce56714611d385780633a04801d14611cfd578063532338f814611cc25780635909c0d514611c8757806359e741d214611c4d5780635a3d549314611c125780636a627842146117db57806370a0823114611778578063715821fe146117155780637464fc3d146116da57806389afcb441461129057806395d89b4114611217578063a4617f3d146111a9578063a9059cbb146110ae578063b499bcbf14611073578063ba9a7a5614611039578063bc25cf7714610e32578063c45a015514610dde578063d21220a714610d8d578063d7dc4e4314610479578063dd62ed3e146103e2578063f40246ee1461039d5763fff6cae914610185575f80fd5b3461039a57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261039a5760ff815c166103725760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825c1617815d6024602073ffffffffffffffffffffffffffffffffffffffff60055416604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa8015610367578290610334575b60249150602073ffffffffffffffffffffffffffffffffffffffff60065416604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156103295783916102ef575b6102c69250600854916dffffffffffffffffffffffffffff808460701c16931691612d77565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c16815d80f35b90506020823d602011610321575b8161030a602093836122db565b8101031261031d576102c69151906102a0565b5f80fd5b3d91506102fd565b6040513d85823e3d90fd5b506020813d60201161035f575b8161034e602093836122db565b8101031261031d5760249051610241565b3d9150610341565b6040513d84823e3d90fd5b807f3ee5aeb50000000000000000000000000000000000000000000000000000000060049252fd5b80fd5b503461039a57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261039a5760406103d66127db565b82519182526020820152f35b503461039a5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261039a5761041a612391565b906024359173ffffffffffffffffffffffffffffffffffffffff831683036104755773ffffffffffffffffffffffffffffffffffffffff918260409216815260036020522091165f52602052602060405f2054604051908152f35b5080fd5b503461031d5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576004356024356044359073ffffffffffffffffffffffffffffffffffffffff82169283830361031d5760643573ffffffffffffffffffffffffffffffffffffffff81169485820361031d576084359267ffffffffffffffff841161031d573660238501121561031d5783600401359067ffffffffffffffff821161031d57366024838701011161031d5760ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d801580158091610d5c575b15610d34576105a86008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b509790966dffffffffffffffffffffffffffff88169485851080610d1b575b15610cf35773ffffffffffffffffffffffffffffffffffffffff600554169173ffffffffffffffffffffffffffffffffffffffff600654169b8389141580610ce9575b15610cc157848f96918e92610cb1575b81610ca0575b50505081610bd3575b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481855afa908115610bc8578491610b90575b506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152999060208b6024818f5afa9a8b15610b8557859b610b4e575b5085870380821115610b46578103965b6dffffffffffffffffffffffffffff83169585870390818e1115610b3e57508c03955b8815801590610b35575b15610b0c5760075461271084028481046127101485151715610adc576107228f9161071c848e612440565b90612426565b916127108202918083046127101490151715610aab579161074e6107549261071c61075a96958d612440565b90612440565b92612440565b60019061271060025b60018111610a645750807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311610a37576107a0920290612440565b11610a0f578d600491602073ffffffffffffffffffffffffffffffffffffffff845460081c16604051948580927f017e7e580000000000000000000000000000000000000000000000000000000082525afa928315610367578b92936109b3575b5082610821939261082a96610816938c612f1e565b9b919e909d88612f1e565b9a91909c612d77565b61084c6008546dffffffffffffffffffffffffffff808260701c169116612440565b61085a8c5460015490612426565b806109ae575060015b61087a61086f836129fb565b61071c600b546129fb565b8060801b908082047001000000000000000000000000000000001490151715610981577fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822937f4f5cb660ad56734b092725a73e127cf47d4d2dc27c12d43c003e3daa7b8f660a9c9b9a9896936109046108fc6109559c9a989561092f956127a4565b600c54612433565b600c55600b556040519384933397859094939260609260808301968352602083015260408201520152565b0390a3604051948594859094939260609260808301968352602083015260408201520152565b0390a27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c16815d80f35b60248e7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b610863565b915091506020813d602011610a07575b816109d0602093836122db565b81010312610a0357519273ffffffffffffffffffffffffffffffffffffffff84168403610a035792908990610816610801565b8e80fd5b3d91506109c3565b60048e7f4a7d1c0f000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111610a375760018216610aa2575b80029060011c610763565b80930292610a97565b5050505060248f7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50505060248f7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b5060048f7f098fb561000000000000000000000000000000000000000000000000000000008152fd5b508615156106f1565b9050956106e7565b5084966106c4565b945099506020843d602011610b7d575b81610b6b602093836122db565b8101031261031d578c9351995f6106b4565b3d9150610b5e565b6040513d87823e3d90fd5b9350506020833d602011610bc0575b81610bac602093836122db565b8101031261031d5791518b9290602461066e565b3d9150610b9f565b6040513d86823e3d90fd5b9091929350863b1561031d57602460a45f927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8660405197889687957fc9ef20e70000000000000000000000000000000000000000000000000000000087523360048801528d828801528c60448801526080606488015282608488015201868601378685828601015201168101030181838a5af18015610c9557610c7e575b90818c9392610629565b610c8c91929b505f906122db565b5f99905f610c74565b6040513d5f823e3d90fd5b610ca992612c0c565b8b845f610620565b610cbc898288612c0c565b61061a565b7f290fa188000000000000000000000000000000000000000000000000000000005f5260045ffd5b508c89141561060a565b7fbb55fd27000000000000000000000000000000000000000000000000000000005f5260045ffd5b506dffffffffffffffffffffffffffff8a1683106105c7565b7f42301c23000000000000000000000000000000000000000000000000000000005f5260045ffd5b50861515610570565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602073ffffffffffffffffffffffffffffffffffffffff60045460081c16604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57610e69612391565b60ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d73ffffffffffffffffffffffffffffffffffffffff6005541673ffffffffffffffffffffffffffffffffffffffff6006541690604051907f70a08231000000000000000000000000000000000000000000000000000000008252306004830152602082602481845afa918215610c955784905f93611001575b50610f35610f3b936dffffffffffffffffffffffffffff6008541690612426565b91612c0c565b604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481855afa928315610c95575f93610fcb575b50610f35610fa3936dffffffffffffffffffffffffffff60085460701c1690612426565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c165f5d005b92506020833d602011610ff9575b81610fe6602093836122db565b8101031261031d57915191610f35610f7f565b3d9150610fd9565b9250506020823d602011611031575b8161101d602093836122db565b8101031261031d5790519083610f35610f14565b3d9150611010565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760206040516103e88152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600154604051908152f35b3461031d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576110e5612391565b6024353361119b575b73ffffffffffffffffffffffffffffffffffffffff821691821590811561118c575b50611178575b335f52600260205260405f2061112d828254612426565b9055815f52600260205260405f208181540190556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3602060405160018152f35b61118481600154612433565b600155611116565b61119590612997565b83611110565b6111a433612997565b6110ee565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57604073ffffffffffffffffffffffffffffffffffffffff6005541673ffffffffffffffffffffffffffffffffffffffff6006541682519182526020820152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5761128c6040516112566040826122db565b600781527f4f55542d414d4d00000000000000000000000000000000000000000000000000602082015260405191829182612349565b0390f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576112c7612391565b60ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d61132c6008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b50909173ffffffffffffffffffffffffffffffffffffffff600554169073ffffffffffffffffffffffffffffffffffffffff6006541692604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481845afa938415610c95575f946116a6575b50604051947f70a08231000000000000000000000000000000000000000000000000000000008652306004870152602086602481845afa958615610c95575f96611672575b50305f52600260205261142761141b61141b61142060405f205498611412600b546129fb565b9384918b612440565b6127a4565b9888612440565b9486151580611669575b15611641576024925f6020923082526002845260408220611453828254612426565b90558082540382556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843092a3611491888783612c0c565b61149c878785612c0c565b604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610c95575f9261160c575b50906020602492604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610c95575f926115d1575b50956115329291604097612d77565b6115546008546dffffffffffffffffffffffffffff808260701c169116612440565b600b5573ffffffffffffffffffffffffffffffffffffffff84519184835283602084015216907fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496853392a37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c165f5d82519182526020820152f35b929150956020833d602011611604575b816115ee602093836122db565b8101031261031d57915191959091906040611523565b3d91506115e1565b91506020823d602011611639575b81611627602093836122db565b8101031261031d5790519060206114dc565b3d915061161a565b7f749383ad000000000000000000000000000000000000000000000000000000005f5260045ffd5b50851515611431565b9095506020813d60201161169e575b8161168e602093836122db565b8101031261031d575194876113ec565b3d9150611681565b9093506020813d6020116116d2575b816116c2602093836122db565b8101031261031d575192866113a7565b3d91506116b5565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600b54604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5773ffffffffffffffffffffffffffffffffffffffff611761612391565b165f52600d602052602060405f2054604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5773ffffffffffffffffffffffffffffffffffffffff6117c4612391565b165f526002602052602060405f2054604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57611812612391565b60ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d60246118796008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b50602073ffffffffffffffffffffffffffffffffffffffff60055416604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa928315610c95575f93611bdd575b5060249293602073ffffffffffffffffffffffffffffffffffffffff60065416604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa938415610c95575f94611ba9575b506dffffffffffffffffffffffffffff8316906119528287612426565b926dffffffffffffffffffffffffffff81169461196f8688612426565b9373ffffffffffffffffffffffffffffffffffffffff8416968715948515611b9a575b505f54611b5c5750506119ad6119a88587612440565b6129fb565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc188101908111610a3757966001546103e88101809111610a37576001555f546103e88101809111610a37575f555f8052600260205260405f206103e881540190555f807fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206040516103e88152a35b8715611b3457602098611a9d94611b20575b611a5a895f54612433565b5f55875f5260028a5260405f20898154019055875f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c6040518d8152a3612d77565b611abf6008546dffffffffffffffffffffffffffff808260701c169116612440565b600b55604051918252848201527f2f00e3cdd69a77be7ed215ec7b2a36784dd158f921fca79ac29deffa353fe6ee60403392a37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c165f5d604051908152f35b611b2c89600154612433565b600155611a4f565b7fd226f9d4000000000000000000000000000000000000000000000000000000005f5260045ffd5b611b839061141b611b7c611b71600b546129fb565b9461141b868c612440565b9388612440565b80821015611b9357505b96611a3d565b9050611b8d565b611ba390612997565b8a611992565b9093506020813d602011611bd5575b81611bc5602093836122db565b8101031261031d57519285611935565b3d9150611bb8565b92506020833d602011611c0a575b81611bf8602093836122db565b8101031261031d5760249251926118d5565b3d9150611beb565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600a54604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760206040516127108152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600954604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600c54604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600754604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602060405160128152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760406103d6612453565b3461031d577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020611dda366123b4565b73ffffffffffffffffffffffffffffffffffffffff8394929593169384611ec9575b5073ffffffffffffffffffffffffffffffffffffffff8516948515908115611eba575b505f85815260038452604080822033835285529020548260018201611e95575b5050611e81575b835f526002825260405f20611e5c828254612426565b9055845f526002825260405f20818154019055604051908152a3602060405160018152f35b611e8d81600154612433565b600155611e46565b611e9e91612426565b5f86815260038552604080822033835286529020558682611e3f565b611ec390612997565b86611e1f565b611ed290612997565b85611dfc565b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5773ffffffffffffffffffffffffffffffffffffffff611f24612391565b165f52600e602052602060405f2054604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760205f54604051908152f35b3461031d57611f83366123b4565b600454919260ff831661207a576127108210156120525760019373ffffffffffffffffffffffffffffffffffffffff8092167fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555167fffffffffffffffffffffffff000000000000000000000000000000000000000060065416176006556007557fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffffffffffffffffffffffffffffffffff003360081b16911617176004555f80f35b7f4209c86e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602060ff600454166040519015158152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b3461031d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5761216a612391565b73ffffffffffffffffffffffffffffffffffffffff60243591335f52600360205260405f208282165f526020528260405f205560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760606dffffffffffffffffffffffffffff63ffffffff61224d6008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b9193908160405195168552166020840152166040820152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5761128c6040516122a56040826122db565b600a81527f4f757472756e20414d4d00000000000000000000000000000000000000000000602082015260405191829182612349565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761231c57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361031d57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606091011261031d5760043573ffffffffffffffffffffffffffffffffffffffff8116810361031d579060243573ffffffffffffffffffffffffffffffffffffffff8116810361031d579060443590565b91908203918211610a3757565b91908201809211610a3757565b81810292918115918404141715610a3757565b61245c33612997565b335f52600e60205260405f205490811561279d57335f52600e6020525f604081205573ffffffffffffffffffffffffffffffffffffffff600554169073ffffffffffffffffffffffffffffffffffffffff60065416916040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481855afa908115610c95575f9161276b575b506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481885afa908115610c95575f91612739575b50612545600b546129fb565b908160801b916fffffffffffffffffffffffffffffffff811603610a375761257d828461257682612583978c612b40565b5089612b40565b96612b40565b9284151580612730575b15612708576024916020916125a3873384612c0c565b6125ae863383612c0c565b6125e16008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b50939092604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa938415610c95575f946126d3575b50926020602494604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610c95575f9161269d575b6126769450612d77565b6126986008546dffffffffffffffffffffffffffff808260701c169116612440565b600b55565b90506020843d6020116126cb575b816126b8602093836122db565b8101031261031d5761267693519061266c565b3d91506126ab565b93506020843d602011612700575b816126ee602093836122db565b8101031261031d579251926020612625565b3d91506126e1565b7f65039130000000000000000000000000000000000000000000000000000000005f5260045ffd5b5083151561258d565b90506020813d602011612763575b81612754602093836122db565b8101031261031d57515f612539565b3d9150612747565b90506020813d602011612795575b81612786602093836122db565b8101031261031d57515f6124f5565b3d9150612779565b5f91508190565b81156127ae570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b335f52600260205261280460405f205461074e600c54335f52600d60205260405f205490612426565b90335f52600e60205260405f20549180612986575b50811561279d57602461282d600b546129fb565b602073ffffffffffffffffffffffffffffffffffffffff60055416604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610c95575f92612952575b508060801b906fffffffffffffffffffffffffffffffff811603610a37576128b38160249386612b40565b93602073ffffffffffffffffffffffffffffffffffffffff60065416604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610c95575f9161291c575b6129199350612b40565b90565b90506020833d60201161294a575b81612937602093836122db565b8101031261031d5761291992519061290f565b3d915061292a565b9091506020813d60201161297e575b8161296e602093836122db565b8101031261031d5751905f612888565b3d9150612961565b6129909192612433565b905f612819565b73ffffffffffffffffffffffffffffffffffffffff600c549116805f52600260205260405f2054815f52600d60205260405f2054830302806129e3575b505f52600d60205260405f2055565b815f52600e60205260405f209081540190555f6129d4565b8015612b3b57612ac96001825f908460801c80612b2f575b508060401c80612b22575b508060201c80612b15575b508060101c80612b08575b508060081c80612afb575b508060041c80612aee575b508060021c80612ae1575b50821c612ada575b811c1b612a6a81846127a4565b0160011c612a7881846127a4565b0160011c612a8681846127a4565b0160011c612a9481846127a4565b0160011c612aa281846127a4565b0160011c612ab081846127a4565b0160011c612abe81846127a4565b0160011c80926127a4565b80821015612ad5575090565b905090565b8101612a5d565b600291509101905f612a55565b600491509101905f612a4a565b600891509101905f612a3f565b601091509101905f612a34565b602091509101905f612a29565b604091509101905f612a1e565b9150506080905f612a13565b505f90565b9091828202917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84820993838086109503948086039514612bff5784831115612bd757829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f227bc153000000000000000000000000000000000000000000000000000000005f5260045ffd5b50509061291992506127a4565b5f928380937fffffffff0000000000000000000000000000000000000000000000000000000060196020604051612c446040826122db565b828152017f7472616e7366657228616464726573732c75696e743235362900000000000000815220169273ffffffffffffffffffffffffffffffffffffffff6040519260208401958652166024830152604482015260448152612ca86064826122db565b51925af13d15612d70573d67ffffffffffffffff811161231c5760405190612cf8601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016602001836122db565b81523d5f602083013e5b81612d38575b5015612d1057565b7f90b8ec18000000000000000000000000000000000000000000000000000000005f5260045ffd5b8051801592508215612d4d575b50505f612d08565b819250906020918101031261031d5760200151801515810361031d575f80612d45565b6060612d02565b916dffffffffffffffffffffffffffff83111580612f06575b15612ede576dffffffffffffffffffffffffffff60409381927f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad19663ffffffff60085460e01c81421603169182151580612ed3575b80612ec8575b612e55575b5050501691827bffffffffffffffffffffffffffff00000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000004260e01b169260701b16171780600855835192835260701c166020820152a1565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff917bffffffffffffffffffffffffffff0000000000000000000000000000612eb7928585612ea583858760701b16612fea565b16026009540160095560701b16612fea565b1602600a5401600a555f8080612df0565b508482161515612deb565b508481161515612de5565b7f35278d12000000000000000000000000000000000000000000000000000000005f5260045ffd5b506dffffffffffffffffffffffffffff821115612d90565b93909294919484158015612fcc575b612fc0576007549073ffffffffffffffffffffffffffffffffffffffff8116612f78575090619c40612f63612f76935f97612440565b0490612f70828096612426565b96612c0c565b565b9591612f7692612fbb61c350612f9e62030d40612f95878c612440565b0495869a612440565b0493612fb485612faf83829b612426565b612426565b9983612c0c565b612c0c565b509193505f9250829150565b5073ffffffffffffffffffffffffffffffffffffffff821615612f2d565b906dffffffffffffffffffffffffffff169081156127ae577bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16049056fea2646970667358221220c5de922d04fb8fd7a8d7bb9d4cd19926116d67afd300354c5eaadf4cbed9c22564736f6c634300081c0033
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f5f3560e01c806306fdde03146122665780630902f1ac146121d6578063095ea7b3146121335780630dfe1681146120e2578063158ef93e146120a25780631794bb3c14611f7557806318160ddd14611f3b57806322a6984014611ed857806323b872dd14611da95780632f1f0c4e14611d71578063313ce56714611d385780633a04801d14611cfd578063532338f814611cc25780635909c0d514611c8757806359e741d214611c4d5780635a3d549314611c125780636a627842146117db57806370a0823114611778578063715821fe146117155780637464fc3d146116da57806389afcb441461129057806395d89b4114611217578063a4617f3d146111a9578063a9059cbb146110ae578063b499bcbf14611073578063ba9a7a5614611039578063bc25cf7714610e32578063c45a015514610dde578063d21220a714610d8d578063d7dc4e4314610479578063dd62ed3e146103e2578063f40246ee1461039d5763fff6cae914610185575f80fd5b3461039a57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261039a5760ff815c166103725760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825c1617815d6024602073ffffffffffffffffffffffffffffffffffffffff60055416604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa8015610367578290610334575b60249150602073ffffffffffffffffffffffffffffffffffffffff60065416604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa9081156103295783916102ef575b6102c69250600854916dffffffffffffffffffffffffffff808460701c16931691612d77565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c16815d80f35b90506020823d602011610321575b8161030a602093836122db565b8101031261031d576102c69151906102a0565b5f80fd5b3d91506102fd565b6040513d85823e3d90fd5b506020813d60201161035f575b8161034e602093836122db565b8101031261031d5760249051610241565b3d9150610341565b6040513d84823e3d90fd5b807f3ee5aeb50000000000000000000000000000000000000000000000000000000060049252fd5b80fd5b503461039a57807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261039a5760406103d66127db565b82519182526020820152f35b503461039a5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261039a5761041a612391565b906024359173ffffffffffffffffffffffffffffffffffffffff831683036104755773ffffffffffffffffffffffffffffffffffffffff918260409216815260036020522091165f52602052602060405f2054604051908152f35b5080fd5b503461031d5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576004356024356044359073ffffffffffffffffffffffffffffffffffffffff82169283830361031d5760643573ffffffffffffffffffffffffffffffffffffffff81169485820361031d576084359267ffffffffffffffff841161031d573660238501121561031d5783600401359067ffffffffffffffff821161031d57366024838701011161031d5760ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d801580158091610d5c575b15610d34576105a86008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b509790966dffffffffffffffffffffffffffff88169485851080610d1b575b15610cf35773ffffffffffffffffffffffffffffffffffffffff600554169173ffffffffffffffffffffffffffffffffffffffff600654169b8389141580610ce9575b15610cc157848f96918e92610cb1575b81610ca0575b50505081610bd3575b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481855afa908115610bc8578491610b90575b506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152999060208b6024818f5afa9a8b15610b8557859b610b4e575b5085870380821115610b46578103965b6dffffffffffffffffffffffffffff83169585870390818e1115610b3e57508c03955b8815801590610b35575b15610b0c5760075461271084028481046127101485151715610adc576107228f9161071c848e612440565b90612426565b916127108202918083046127101490151715610aab579161074e6107549261071c61075a96958d612440565b90612440565b92612440565b60019061271060025b60018111610a645750807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311610a37576107a0920290612440565b11610a0f578d600491602073ffffffffffffffffffffffffffffffffffffffff845460081c16604051948580927f017e7e580000000000000000000000000000000000000000000000000000000082525afa928315610367578b92936109b3575b5082610821939261082a96610816938c612f1e565b9b919e909d88612f1e565b9a91909c612d77565b61084c6008546dffffffffffffffffffffffffffff808260701c169116612440565b61085a8c5460015490612426565b806109ae575060015b61087a61086f836129fb565b61071c600b546129fb565b8060801b908082047001000000000000000000000000000000001490151715610981577fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822937f4f5cb660ad56734b092725a73e127cf47d4d2dc27c12d43c003e3daa7b8f660a9c9b9a9896936109046108fc6109559c9a989561092f956127a4565b600c54612433565b600c55600b556040519384933397859094939260609260808301968352602083015260408201520152565b0390a3604051948594859094939260609260808301968352602083015260408201520152565b0390a27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c16815d80f35b60248e7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b610863565b915091506020813d602011610a07575b816109d0602093836122db565b81010312610a0357519273ffffffffffffffffffffffffffffffffffffffff84168403610a035792908990610816610801565b8e80fd5b3d91506109c3565b60048e7f4a7d1c0f000000000000000000000000000000000000000000000000000000008152fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111610a375760018216610aa2575b80029060011c610763565b80930292610a97565b5050505060248f7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b50505060248f7f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b5060048f7f098fb561000000000000000000000000000000000000000000000000000000008152fd5b508615156106f1565b9050956106e7565b5084966106c4565b945099506020843d602011610b7d575b81610b6b602093836122db565b8101031261031d578c9351995f6106b4565b3d9150610b5e565b6040513d87823e3d90fd5b9350506020833d602011610bc0575b81610bac602093836122db565b8101031261031d5791518b9290602461066e565b3d9150610b9f565b6040513d86823e3d90fd5b9091929350863b1561031d57602460a45f927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8660405197889687957fc9ef20e70000000000000000000000000000000000000000000000000000000087523360048801528d828801528c60448801526080606488015282608488015201868601378685828601015201168101030181838a5af18015610c9557610c7e575b90818c9392610629565b610c8c91929b505f906122db565b5f99905f610c74565b6040513d5f823e3d90fd5b610ca992612c0c565b8b845f610620565b610cbc898288612c0c565b61061a565b7f290fa188000000000000000000000000000000000000000000000000000000005f5260045ffd5b508c89141561060a565b7fbb55fd27000000000000000000000000000000000000000000000000000000005f5260045ffd5b506dffffffffffffffffffffffffffff8a1683106105c7565b7f42301c23000000000000000000000000000000000000000000000000000000005f5260045ffd5b50861515610570565b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602073ffffffffffffffffffffffffffffffffffffffff60045460081c16604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57610e69612391565b60ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d73ffffffffffffffffffffffffffffffffffffffff6005541673ffffffffffffffffffffffffffffffffffffffff6006541690604051907f70a08231000000000000000000000000000000000000000000000000000000008252306004830152602082602481845afa918215610c955784905f93611001575b50610f35610f3b936dffffffffffffffffffffffffffff6008541690612426565b91612c0c565b604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481855afa928315610c95575f93610fcb575b50610f35610fa3936dffffffffffffffffffffffffffff60085460701c1690612426565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c165f5d005b92506020833d602011610ff9575b81610fe6602093836122db565b8101031261031d57915191610f35610f7f565b3d9150610fd9565b9250506020823d602011611031575b8161101d602093836122db565b8101031261031d5790519083610f35610f14565b3d9150611010565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760206040516103e88152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600154604051908152f35b3461031d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576110e5612391565b6024353361119b575b73ffffffffffffffffffffffffffffffffffffffff821691821590811561118c575b50611178575b335f52600260205260405f2061112d828254612426565b9055815f52600260205260405f208181540190556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3602060405160018152f35b61118481600154612433565b600155611116565b61119590612997565b83611110565b6111a433612997565b6110ee565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57604073ffffffffffffffffffffffffffffffffffffffff6005541673ffffffffffffffffffffffffffffffffffffffff6006541682519182526020820152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5761128c6040516112566040826122db565b600781527f4f55542d414d4d00000000000000000000000000000000000000000000000000602082015260405191829182612349565b0390f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576112c7612391565b60ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d61132c6008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b50909173ffffffffffffffffffffffffffffffffffffffff600554169073ffffffffffffffffffffffffffffffffffffffff6006541692604051927f70a08231000000000000000000000000000000000000000000000000000000008452306004850152602084602481845afa938415610c95575f946116a6575b50604051947f70a08231000000000000000000000000000000000000000000000000000000008652306004870152602086602481845afa958615610c95575f96611672575b50305f52600260205261142761141b61141b61142060405f205498611412600b546129fb565b9384918b612440565b6127a4565b9888612440565b9486151580611669575b15611641576024925f6020923082526002845260408220611453828254612426565b90558082540382556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef843092a3611491888783612c0c565b61149c878785612c0c565b604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610c95575f9261160c575b50906020602492604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610c95575f926115d1575b50956115329291604097612d77565b6115546008546dffffffffffffffffffffffffffff808260701c169116612440565b600b5573ffffffffffffffffffffffffffffffffffffffff84519184835283602084015216907fdccd412f0b1252819cb1fd330b93224ca42612892bb3f4f789976e6d81936496853392a37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c165f5d82519182526020820152f35b929150956020833d602011611604575b816115ee602093836122db565b8101031261031d57915191959091906040611523565b3d91506115e1565b91506020823d602011611639575b81611627602093836122db565b8101031261031d5790519060206114dc565b3d915061161a565b7f749383ad000000000000000000000000000000000000000000000000000000005f5260045ffd5b50851515611431565b9095506020813d60201161169e575b8161168e602093836122db565b8101031261031d575194876113ec565b3d9150611681565b9093506020813d6020116116d2575b816116c2602093836122db565b8101031261031d575192866113a7565b3d91506116b5565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600b54604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5773ffffffffffffffffffffffffffffffffffffffff611761612391565b165f52600d602052602060405f2054604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5773ffffffffffffffffffffffffffffffffffffffff6117c4612391565b165f526002602052602060405f2054604051908152f35b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57611812612391565b60ff5f5c16610d655760017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c16175f5d60246118796008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b50602073ffffffffffffffffffffffffffffffffffffffff60055416604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa928315610c95575f93611bdd575b5060249293602073ffffffffffffffffffffffffffffffffffffffff60065416604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa938415610c95575f94611ba9575b506dffffffffffffffffffffffffffff8316906119528287612426565b926dffffffffffffffffffffffffffff81169461196f8688612426565b9373ffffffffffffffffffffffffffffffffffffffff8416968715948515611b9a575b505f54611b5c5750506119ad6119a88587612440565b6129fb565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc188101908111610a3757966001546103e88101809111610a37576001555f546103e88101809111610a37575f555f8052600260205260405f206103e881540190555f807fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60206040516103e88152a35b8715611b3457602098611a9d94611b20575b611a5a895f54612433565b5f55875f5260028a5260405f20898154019055875f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c6040518d8152a3612d77565b611abf6008546dffffffffffffffffffffffffffff808260701c169116612440565b600b55604051918252848201527f2f00e3cdd69a77be7ed215ec7b2a36784dd158f921fca79ac29deffa353fe6ee60403392a37fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff005f5c165f5d604051908152f35b611b2c89600154612433565b600155611a4f565b7fd226f9d4000000000000000000000000000000000000000000000000000000005f5260045ffd5b611b839061141b611b7c611b71600b546129fb565b9461141b868c612440565b9388612440565b80821015611b9357505b96611a3d565b9050611b8d565b611ba390612997565b8a611992565b9093506020813d602011611bd5575b81611bc5602093836122db565b8101031261031d57519285611935565b3d9150611bb8565b92506020833d602011611c0a575b81611bf8602093836122db565b8101031261031d5760249251926118d5565b3d9150611beb565b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600a54604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760206040516127108152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600954604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600c54604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d576020600754604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602060405160128152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760406103d6612453565b3461031d577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef6020611dda366123b4565b73ffffffffffffffffffffffffffffffffffffffff8394929593169384611ec9575b5073ffffffffffffffffffffffffffffffffffffffff8516948515908115611eba575b505f85815260038452604080822033835285529020548260018201611e95575b5050611e81575b835f526002825260405f20611e5c828254612426565b9055845f526002825260405f20818154019055604051908152a3602060405160018152f35b611e8d81600154612433565b600155611e46565b611e9e91612426565b5f86815260038552604080822033835286529020558682611e3f565b611ec390612997565b86611e1f565b611ed290612997565b85611dfc565b3461031d5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5773ffffffffffffffffffffffffffffffffffffffff611f24612391565b165f52600e602052602060405f2054604051908152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760205f54604051908152f35b3461031d57611f83366123b4565b600454919260ff831661207a576127108210156120525760019373ffffffffffffffffffffffffffffffffffffffff8092167fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555167fffffffffffffffffffffffff000000000000000000000000000000000000000060065416176006556007557fffffffffffffffffffffff00000000000000000000000000000000000000000074ffffffffffffffffffffffffffffffffffffffff003360081b16911617176004555f80f35b7f4209c86e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7ff92ee8a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602060ff600454166040519015158152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d57602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b3461031d5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5761216a612391565b73ffffffffffffffffffffffffffffffffffffffff60243591335f52600360205260405f208282165f526020528260405f205560405192835216907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5760606dffffffffffffffffffffffffffff63ffffffff61224d6008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b9193908160405195168552166020840152166040820152f35b3461031d575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261031d5761128c6040516122a56040826122db565b600a81527f4f757472756e20414d4d00000000000000000000000000000000000000000000602082015260405191829182612349565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761231c57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602060409481855280519182918282880152018686015e5f8582860101520116010190565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361031d57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606091011261031d5760043573ffffffffffffffffffffffffffffffffffffffff8116810361031d579060243573ffffffffffffffffffffffffffffffffffffffff8116810361031d579060443590565b91908203918211610a3757565b91908201809211610a3757565b81810292918115918404141715610a3757565b61245c33612997565b335f52600e60205260405f205490811561279d57335f52600e6020525f604081205573ffffffffffffffffffffffffffffffffffffffff600554169073ffffffffffffffffffffffffffffffffffffffff60065416916040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481855afa908115610c95575f9161276b575b506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481885afa908115610c95575f91612739575b50612545600b546129fb565b908160801b916fffffffffffffffffffffffffffffffff811603610a375761257d828461257682612583978c612b40565b5089612b40565b96612b40565b9284151580612730575b15612708576024916020916125a3873384612c0c565b6125ae863383612c0c565b6125e16008546dffffffffffffffffffffffffffff8116916dffffffffffffffffffffffffffff8260701c169160e01c90565b50939092604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa938415610c95575f946126d3575b50926020602494604051958680927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610c95575f9161269d575b6126769450612d77565b6126986008546dffffffffffffffffffffffffffff808260701c169116612440565b600b55565b90506020843d6020116126cb575b816126b8602093836122db565b8101031261031d5761267693519061266c565b3d91506126ab565b93506020843d602011612700575b816126ee602093836122db565b8101031261031d579251926020612625565b3d91506126e1565b7f65039130000000000000000000000000000000000000000000000000000000005f5260045ffd5b5083151561258d565b90506020813d602011612763575b81612754602093836122db565b8101031261031d57515f612539565b3d9150612747565b90506020813d602011612795575b81612786602093836122db565b8101031261031d57515f6124f5565b3d9150612779565b5f91508190565b81156127ae570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b335f52600260205261280460405f205461074e600c54335f52600d60205260405f205490612426565b90335f52600e60205260405f20549180612986575b50811561279d57602461282d600b546129fb565b602073ffffffffffffffffffffffffffffffffffffffff60055416604051938480927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa918215610c95575f92612952575b508060801b906fffffffffffffffffffffffffffffffff811603610a37576128b38160249386612b40565b93602073ffffffffffffffffffffffffffffffffffffffff60065416604051948580927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610c95575f9161291c575b6129199350612b40565b90565b90506020833d60201161294a575b81612937602093836122db565b8101031261031d5761291992519061290f565b3d915061292a565b9091506020813d60201161297e575b8161296e602093836122db565b8101031261031d5751905f612888565b3d9150612961565b6129909192612433565b905f612819565b73ffffffffffffffffffffffffffffffffffffffff600c549116805f52600260205260405f2054815f52600d60205260405f2054830302806129e3575b505f52600d60205260405f2055565b815f52600e60205260405f209081540190555f6129d4565b8015612b3b57612ac96001825f908460801c80612b2f575b508060401c80612b22575b508060201c80612b15575b508060101c80612b08575b508060081c80612afb575b508060041c80612aee575b508060021c80612ae1575b50821c612ada575b811c1b612a6a81846127a4565b0160011c612a7881846127a4565b0160011c612a8681846127a4565b0160011c612a9481846127a4565b0160011c612aa281846127a4565b0160011c612ab081846127a4565b0160011c612abe81846127a4565b0160011c80926127a4565b80821015612ad5575090565b905090565b8101612a5d565b600291509101905f612a55565b600491509101905f612a4a565b600891509101905f612a3f565b601091509101905f612a34565b602091509101905f612a29565b604091509101905f612a1e565b9150506080905f612a13565b505f90565b9091828202917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84820993838086109503948086039514612bff5784831115612bd757829109815f0382168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f227bc153000000000000000000000000000000000000000000000000000000005f5260045ffd5b50509061291992506127a4565b5f928380937fffffffff0000000000000000000000000000000000000000000000000000000060196020604051612c446040826122db565b828152017f7472616e7366657228616464726573732c75696e743235362900000000000000815220169273ffffffffffffffffffffffffffffffffffffffff6040519260208401958652166024830152604482015260448152612ca86064826122db565b51925af13d15612d70573d67ffffffffffffffff811161231c5760405190612cf8601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016602001836122db565b81523d5f602083013e5b81612d38575b5015612d1057565b7f90b8ec18000000000000000000000000000000000000000000000000000000005f5260045ffd5b8051801592508215612d4d575b50505f612d08565b819250906020918101031261031d5760200151801515810361031d575f80612d45565b6060612d02565b916dffffffffffffffffffffffffffff83111580612f06575b15612ede576dffffffffffffffffffffffffffff60409381927f1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad19663ffffffff60085460e01c81421603169182151580612ed3575b80612ec8575b612e55575b5050501691827bffffffffffffffffffffffffffff00000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000004260e01b169260701b16171780600855835192835260701c166020820152a1565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff917bffffffffffffffffffffffffffff0000000000000000000000000000612eb7928585612ea583858760701b16612fea565b16026009540160095560701b16612fea565b1602600a5401600a555f8080612df0565b508482161515612deb565b508481161515612de5565b7f35278d12000000000000000000000000000000000000000000000000000000005f5260045ffd5b506dffffffffffffffffffffffffffff821115612d90565b93909294919484158015612fcc575b612fc0576007549073ffffffffffffffffffffffffffffffffffffffff8116612f78575090619c40612f63612f76935f97612440565b0490612f70828096612426565b96612c0c565b565b9591612f7692612fbb61c350612f9e62030d40612f95878c612440565b0495869a612440565b0493612fb485612faf83829b612426565b612426565b9983612c0c565b612c0c565b509193505f9250829150565b5073ffffffffffffffffffffffffffffffffffffffff821615612f2d565b906dffffffffffffffffffffffffffff169081156127ae577bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16049056fea2646970667358221220c5de922d04fb8fd7a8d7bb9d4cd19926116d67afd300354c5eaadf4cbed9c22564736f6c634300081c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 31 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.