ETH Price: $3,370.24 (+5.12%)
Gas: 0.07 GWei

Contract

0x37BAc764494c8db4e54BDE72f6965beA9fa0AC2d

Overview

ETH Balance

Linea Mainnet LogoLinea Mainnet LogoLinea Mainnet Logo0 ETH

ETH Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Create Pool141639152025-01-04 11:06:5720 days ago1735988817IN
SyncSwap: Classic Pool Factory
0 ETH0.000142640.03804025
Create Pool138620502024-12-27 22:32:4727 days ago1735338767IN
SyncSwap: Classic Pool Factory
0 ETH0.000150840.04068266
Create Pool135595622024-12-20 15:56:3535 days ago1734710195IN
SyncSwap: Classic Pool Factory
0 ETH0.001040570.28090569
Create Pool134491112024-12-18 1:29:0937 days ago1734485349IN
SyncSwap: Classic Pool Factory
0 ETH0.000141430.03817243
Create Pool118777952024-11-10 10:31:4375 days ago1731234703IN
SyncSwap: Classic Pool Factory
0 ETH0.000561580.14974959
Create Pool103319412024-10-05 1:24:56111 days ago1728091496IN
SyncSwap: Classic Pool Factory
0 ETH0.000205260.05517939
Create Pool99289652024-09-25 15:25:04121 days ago1727277904IN
SyncSwap: Classic Pool Factory
0 ETH0.000696990.1883
Create Pool99289002024-09-25 15:22:53121 days ago1727277773IN
SyncSwap: Classic Pool Factory
0 ETH0.000696990.1883
Create Pool99288432024-09-25 15:20:59121 days ago1727277659IN
SyncSwap: Classic Pool Factory
0 ETH0.000701220.1883
Create Pool99287182024-09-25 15:16:49121 days ago1727277409IN
SyncSwap: Classic Pool Factory
0 ETH0.000793590.21183749
Create Pool99286042024-09-25 15:13:01121 days ago1727277181IN
SyncSwap: Classic Pool Factory
0 ETH0.000714380.193
Create Pool99285872024-09-25 15:12:27121 days ago1727277147IN
SyncSwap: Classic Pool Factory
0 ETH0.000723030.193
Create Pool99276862024-09-25 14:42:20121 days ago1727275340IN
SyncSwap: Classic Pool Factory
0 ETH0.000853230.23
Create Pool99275452024-09-25 14:37:38121 days ago1727275058IN
SyncSwap: Classic Pool Factory
0 ETH0.000863530.23
Create Pool99274582024-09-25 14:34:44121 days ago1727274884IN
SyncSwap: Classic Pool Factory
0 ETH0.000863530.23
Create Pool99273212024-09-25 14:30:09121 days ago1727274609IN
SyncSwap: Classic Pool Factory
0 ETH0.000843470.226
Create Pool99271882024-09-25 14:25:43121 days ago1727274343IN
SyncSwap: Classic Pool Factory
0 ETH0.000883320.2365
Create Pool99270852024-09-25 14:22:15121 days ago1727274135IN
SyncSwap: Classic Pool Factory
0 ETH0.000798560.2151
Create Pool99270602024-09-25 14:21:25121 days ago1727274085IN
SyncSwap: Classic Pool Factory
0 ETH0.000797580.215
Create Pool99270382024-09-25 14:20:41121 days ago1727274041IN
SyncSwap: Classic Pool Factory
0 ETH0.000797580.215
Create Pool99268302024-09-25 14:13:45121 days ago1727273625IN
SyncSwap: Classic Pool Factory
0 ETH0.000786470.21
Create Pool99268172024-09-25 14:13:19121 days ago1727273599IN
SyncSwap: Classic Pool Factory
0 ETH0.000791170.21
Create Pool99267842024-09-25 14:12:13121 days ago1727273533IN
SyncSwap: Classic Pool Factory
0 ETH0.000786470.21
Create Pool99267512024-09-25 14:11:07121 days ago1727273467IN
SyncSwap: Classic Pool Factory
0 ETH0.000782630.20881661
Create Pool99267372024-09-25 14:10:39121 days ago1727273439IN
SyncSwap: Classic Pool Factory
0 ETH0.000782350.21
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
149906112025-01-24 17:25:532 hrs ago1737739553
SyncSwap: Classic Pool Factory
0 ETH
149877902025-01-24 15:42:344 hrs ago1737733354
SyncSwap: Classic Pool Factory
0 ETH
149859222025-01-24 14:37:205 hrs ago1737729440
SyncSwap: Classic Pool Factory
0 ETH
149859222025-01-24 14:37:205 hrs ago1737729440
SyncSwap: Classic Pool Factory
0 ETH
149859222025-01-24 14:37:205 hrs ago1737729440
SyncSwap: Classic Pool Factory
0 ETH
149798012025-01-24 11:03:188 hrs ago1737716598
SyncSwap: Classic Pool Factory
0 ETH
149798012025-01-24 11:03:188 hrs ago1737716598
SyncSwap: Classic Pool Factory
0 ETH
149798012025-01-24 11:03:188 hrs ago1737716598
SyncSwap: Classic Pool Factory
0 ETH
149798012025-01-24 11:03:188 hrs ago1737716598
SyncSwap: Classic Pool Factory
0 ETH
149798012025-01-24 11:03:188 hrs ago1737716598
SyncSwap: Classic Pool Factory
0 ETH
149687172025-01-24 4:41:5015 hrs ago1737693710
SyncSwap: Classic Pool Factory
0 ETH
149687172025-01-24 4:41:5015 hrs ago1737693710
SyncSwap: Classic Pool Factory
0 ETH
149687172025-01-24 4:41:5015 hrs ago1737693710
SyncSwap: Classic Pool Factory
0 ETH
149687172025-01-24 4:41:5015 hrs ago1737693710
SyncSwap: Classic Pool Factory
0 ETH
149687172025-01-24 4:41:5015 hrs ago1737693710
SyncSwap: Classic Pool Factory
0 ETH
149612532025-01-24 0:01:1519 hrs ago1737676875
SyncSwap: Classic Pool Factory
0 ETH
149612532025-01-24 0:01:1519 hrs ago1737676875
SyncSwap: Classic Pool Factory
0 ETH
149612532025-01-24 0:01:1519 hrs ago1737676875
SyncSwap: Classic Pool Factory
0 ETH
149592742025-01-23 22:40:1821 hrs ago1737672018
SyncSwap: Classic Pool Factory
0 ETH
149452012025-01-23 14:07:5529 hrs ago1737641275
SyncSwap: Classic Pool Factory
0 ETH
149452012025-01-23 14:07:5529 hrs ago1737641275
SyncSwap: Classic Pool Factory
0 ETH
149452012025-01-23 14:07:5529 hrs ago1737641275
SyncSwap: Classic Pool Factory
0 ETH
149382502025-01-23 10:01:3233 hrs ago1737626492
SyncSwap: Classic Pool Factory
0 ETH
149382502025-01-23 10:01:3233 hrs ago1737626492
SyncSwap: Classic Pool Factory
0 ETH
149382502025-01-23 10:01:3233 hrs ago1737626492
SyncSwap: Classic Pool Factory
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SyncSwapClassicPoolFactory

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 29 : SyncSwapClassicPoolFactory.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

import "../../interfaces/master/IPoolMaster.sol";
import "../../interfaces/token/IERC20.sol";

import "../BasePoolFactory.sol";

import "./SyncSwapClassicPool.sol";

contract SyncSwapClassicPoolFactory is BasePoolFactory {
    constructor(address _master) BasePoolFactory(_master) {
    }

    function _createPool(address token0, address token1) internal override returns (address pool) {
        // Perform sanity checks.
        IERC20(token0).balanceOf(address(this));
        IERC20(token1).balanceOf(address(this));

        bytes memory deployData = abi.encode(token0, token1);
        cachedDeployData = deployData;

        // The salt is same with deployment data.
        bytes32 salt = keccak256(deployData);
        pool = address(new SyncSwapClassicPool{salt: salt}()); // this will prevent duplicated pools.

        // Register the pool. The config is same with deployment data.
        IPoolMaster(master).registerPool(pool, 1, deployData);
    }
}

File 2 of 29 : IBasePoolFactory.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IPoolFactory.sol";

interface IBasePoolFactory is IPoolFactory {
    event PoolCreated(
        address indexed token0,
        address indexed token1,
        address pool
    );

    function getPool(address tokenA, address tokenB) external view returns (address pool);

    function getSwapFee(
        address pool,
        address sender,
        address tokenIn,
        address tokenOut,
        bytes calldata data
    ) external view returns (uint24 swapFee);
}

File 3 of 29 : IPoolFactory.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IPoolFactory {
    function master() external view returns (address);

    function getDeployData() external view returns (bytes memory);

    function createPool(bytes calldata data) external returns (address pool);
}

File 4 of 29 : ICallback.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

/// @dev The callback interface for SyncSwap base pool operations.
/// Note additional checks will be required for some callbacks, see below for more information.
/// Visit the documentation https://syncswap.gitbook.io/api-documentation/ for more details.
interface ICallback {

    struct BaseMintCallbackParams {
        address sender;
        address to;
        uint reserve0;
        uint reserve1;
        uint balance0;
        uint balance1;
        uint amount0;
        uint amount1;
        uint fee0;
        uint fee1;
        uint newInvariant;
        uint oldInvariant;
        uint totalSupply;
        uint liquidity;
        uint24 swapFee;
        bytes callbackData;
    }
    function syncSwapBaseMintCallback(BaseMintCallbackParams calldata params) external;

    struct BaseBurnCallbackParams {
        address sender;
        address to;
        uint balance0;
        uint balance1;
        uint liquidity;
        uint totalSupply;
        uint amount0;
        uint amount1;
        uint8 withdrawMode;
        bytes callbackData;
    }
    function syncSwapBaseBurnCallback(BaseBurnCallbackParams calldata params) external;

    struct BaseBurnSingleCallbackParams {
        address sender;
        address to;
        address tokenIn;
        address tokenOut;
        uint balance0;
        uint balance1;
        uint liquidity;
        uint totalSupply;
        uint amount0;
        uint amount1;
        uint amountOut;
        uint amountSwapped;
        uint feeIn;
        uint24 swapFee;
        uint8 withdrawMode;
        bytes callbackData;
    }
    /// @dev Note the `tokenOut` parameter can be decided by the caller, and the correctness is not guaranteed.
    /// Additional checks MUST be performed in callback to ensure the `tokenOut` is one of the pools tokens if the sender
    /// is not a trusted source to avoid potential issues.
    function syncSwapBaseBurnSingleCallback(BaseBurnSingleCallbackParams calldata params) external;

    struct BaseSwapCallbackParams {
        address sender;
        address to;
        address tokenIn;
        address tokenOut;
        uint reserve0;
        uint reserve1;
        uint balance0;
        uint balance1;
        uint amountIn;
        uint amountOut;
        uint feeIn;
        uint24 swapFee;
        uint8 withdrawMode;
        bytes callbackData;
    }
    /// @dev Note the `tokenIn` parameter can be decided by the caller, and the correctness is not guaranteed.
    /// Additional checks MUST be performed in callback to ensure the `tokenIn` is one of the pools tokens if the sender
    /// is not a trusted source to avoid potential issues.
    function syncSwapBaseSwapCallback(BaseSwapCallbackParams calldata params) external;
}

File 5 of 29 : IFeeManager.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

/// @notice The manager contract to control fees.
/// Management functions are omitted.
interface IFeeManager {
    function getSwapFee(
        address pool,
        address sender,
        address tokenIn,
        address tokenOut,
        bytes calldata data) external view returns (uint24);
    function getProtocolFee(address pool) external view returns (uint24);
    function getFeeRecipient() external view returns (address);
}

File 6 of 29 : IFeeRecipient.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IFeeRecipient {
    /// @dev Notifies the fee recipient after sent fees.
    function notifyFees(
        uint16 feeType,
        address token,
        uint amount,
        uint feeRate,
        bytes calldata data
    ) external;
}

File 7 of 29 : IForwarderRegistry.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IForwarderRegistry {
    function isForwarder(address forwarder) external view returns (bool);
}

File 8 of 29 : IPoolMaster.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IFeeManager.sol";
import "./IForwarderRegistry.sol";

/// @dev The master contract to create pools and manage whitelisted factories.
/// Inheriting the fee manager interface to support fee queries.
interface IPoolMaster is IFeeManager, IForwarderRegistry {
    event SetFactoryWhitelisted(address indexed factory, bool whitelisted);

    event RegisterPool(
        address indexed factory,
        address indexed pool,
        uint16 indexed poolType,
        bytes data
    );

    event UpdateForwarderRegistry(address indexed newForwarderRegistry);

    event UpdateFeeManager(address indexed newFeeManager);

    function vault() external view returns (address);

    function feeManager() external view returns (address);

    function pools(uint) external view returns (address);

    function poolsLength() external view returns (uint);

    // Forwarder Registry
    function setForwarderRegistry(address) external;

    // Fees
    function setFeeManager(address) external;

    // Factories
    function isFactoryWhitelisted(address) external view returns (bool);

    function setFactoryWhitelisted(address factory, bool whitelisted) external;

    // Pools
    function isPool(address) external view returns (bool);

    function getPool(bytes32) external view returns (address);

    function createPool(address factory, bytes calldata data) external returns (address pool);

    function registerPool(address pool, uint16 poolType, bytes calldata data) external;
}

File 9 of 29 : IBasePool.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IPool.sol";
import "../token/IERC20Permit2.sol";

interface IBasePool is IPool, IERC20Permit2 {
    function token0() external view returns (address);
    function token1() external view returns (address);

    function reserve0() external view returns (uint);
    function reserve1() external view returns (uint);
    function invariantLast() external view returns (uint);

    function getReserves() external view returns (uint, uint);
    function getAmountOut(address tokenIn, uint amountIn, address sender) external view returns (uint amountOut);
    function getAmountIn(address tokenOut, uint amountOut, address sender) external view returns (uint amountIn);

    event Mint(
        address indexed sender,
        uint amount0,
        uint amount1,
        uint liquidity,
        address indexed to
    );

    event Burn(
        address indexed sender,
        uint amount0,
        uint amount1,
        uint liquidity,
        address indexed to
    );

    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );

    event Sync(
        uint reserve0,
        uint reserve1
    );
}

File 10 of 29 : IClassicPool.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IBasePool.sol";

interface IClassicPool is IBasePool {
}

File 11 of 29 : IPool.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IPool {
    struct TokenAmount {
        address token;
        uint amount;
    }

    /// @dev Returns the address of pool master.
    function master() external view returns (address);

    /// @dev Returns the vault.
    function vault() external view returns (address);

    /// @dev Returns the pool type.
    function poolType() external view returns (uint16);

    /// @dev Returns the assets of the pool.
    function getAssets() external view returns (address[] memory assets);

    /// @dev Returns the swap fee of the pool.
    function getSwapFee(address sender, address tokenIn, address tokenOut, bytes calldata data) external view returns (uint24 swapFee);

    /// @dev Returns the protocol fee of the pool.
    function getProtocolFee() external view returns (uint24 protocolFee);

    /// @dev Mints liquidity.
    function mint(
        bytes calldata data,
        address sender,
        address callback,
        bytes calldata callbackData
    ) external returns (uint liquidity);

    /// @dev Burns liquidity.
    function burn(
        bytes calldata data,
        address sender,
        address callback,
        bytes calldata callbackData
    ) external returns (TokenAmount[] memory tokenAmounts);

    /// @dev Burns liquidity with single output token.
    function burnSingle(
        bytes calldata data,
        address sender,
        address callback,
        bytes calldata callbackData
    ) external returns (TokenAmount memory tokenAmount);

    /// @dev Swaps between tokens.
    function swap(
        bytes calldata data,
        address sender,
        address callback,
        bytes calldata callbackData
    ) external returns (TokenAmount memory tokenAmount);
}

File 12 of 29 : IERC165.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceID The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceID` and
    ///  `interfaceID` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

File 13 of 29 : IERC20.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IERC20Base.sol";

interface IERC20 is IERC20Base {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
}

File 14 of 29 : IERC20Base.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IERC20Base {
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint amount) external returns (bool);
    function transfer(address to, uint amount) external returns (bool);
    function transferFrom(address from, address to, uint amount) external returns (bool);
    
    event Approval(address indexed owner, address indexed spender, uint amount);
    event Transfer(address indexed from, address indexed to, uint amount);
}

File 15 of 29 : IERC20Permit.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IERC20.sol";

interface IERC20Permit is IERC20 {
    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    function nonces(address owner) external view returns (uint);
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 16 of 29 : IERC20Permit2.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IERC20Permit.sol";

interface IERC20Permit2 is IERC20Permit {
    function permit2(address owner, address spender, uint amount, uint deadline, bytes calldata signature) external;
}

File 17 of 29 : IERC3156FlashBorrower.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IERC3156FlashBorrower {
    /**
     * @dev Receive a flash loan.
     * @param initiator The initiator of the loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param fee The additional amount of tokens to repay.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
     */
    function onFlashLoan(
        address initiator,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata data
    ) external returns (bytes32);
}

File 18 of 29 : IERC3156FlashLender.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IERC3156FlashBorrower.sol";

interface IERC3156FlashLender {
    /**
     * @dev The amount of currency available to be lent.
     * @param token The loan currency.
     * @return The amount of `token` that can be borrowed.
     */
    function maxFlashLoan(
        address token
    ) external view returns (uint256);

    /**
     * @dev The fee to be charged for a given loan.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @return The amount of `token` to be charged for the loan, on top of the returned principal.
     */
    function flashFee(
        address token,
        uint256 amount
    ) external view returns (uint256);

    /**
     * @dev Initiate a flash loan.
     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
     * @param token The loan currency.
     * @param amount The amount of tokens lent.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     */
    function flashLoan(
        IERC3156FlashBorrower receiver,
        address token,
        uint256 amount,
        bytes calldata data
    ) external returns (bool);
}

File 19 of 29 : IFlashLoan.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IFlashLoanRecipient.sol";
import "./IERC3156FlashLender.sol";

interface IFlashLoan is IERC3156FlashLender {
    function flashLoanFeePercentage() external view returns (uint);

    /**
     * @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
     * and then reverting unless the tokens plus a proportional protocol fee have been returned.
     *
     * The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
     * for each token contract. `tokens` must be sorted in ascending order.
     *
     * The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
     * `receiveFlashLoan` call.
     *
     * Emits `FlashLoan` events.
     */
    function flashLoanMultiple(
        IFlashLoanRecipient recipient,
        address[] memory tokens,
        uint[] memory amounts,
        bytes memory userData
    ) external;

    /**
     * @dev Emitted for each individual flash loan performed by `flashLoan`.
     */
    event FlashLoan(address indexed recipient, address indexed token, uint amount, uint feeAmount);
}

File 20 of 29 : IFlashLoanRecipient.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity >=0.7.0 <0.9.0;

// Inspired by Aave Protocol's IFlashLoanReceiver.

interface IFlashLoanRecipient {
    /**
     * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
     *
     * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
     * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
     * Vault, or else the entire flash loan will revert.
     *
     * `userData` is the same value passed in the `IVault.flashLoan` call.
     */
    function receiveFlashLoan(
        address[] memory tokens,
        uint[] memory amounts,
        uint[] memory feeAmounts,
        bytes memory userData
    ) external;
}

File 21 of 29 : IVault.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

import "./IFlashLoan.sol";

interface IVault is IFlashLoan {
    function wETH() external view returns (address);

    function reserves(address token) external view returns (uint reserve);

    function balanceOf(address token, address owner) external view returns (uint balance);

    function deposit(address token, address to) external payable returns (uint amount);

    function depositETH(address to) external payable returns (uint amount);

    function transferAndDeposit(address token, address to, uint amount) external payable returns (uint);

    function transfer(address token, address to, uint amount) external;

    function withdraw(address token, address to, uint amount) external;

    function withdrawAlternative(address token, address to, uint amount, uint8 mode) external;

    function withdrawETH(address to, uint amount) external;
}

File 22 of 29 : ECDSA.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 *
 * Based on OpenZeppelin's ECDSA library.
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/561d1061fc568f04c7a65853538e834a889751e8/contracts/utils/cryptography/ECDSA.sol
 */
library ECDSA {

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            return address(0);
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        /// @solidity memory-safe-assembly
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }

        return ecrecover(hash, v, r, s);
    }
}

File 23 of 29 : ERC20Permit2.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

import "../interfaces/token/IERC165.sol";
import "../interfaces/token/IERC20Permit2.sol";

import "./SignatureChecker.sol";

error Expired();
error InvalidSignature();

/**
 * @dev A simple ERC20 implementation for pool's liquidity token, supports permit by both ECDSA signatures from
 * externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like Argent.
 *
 * Based on Solmate's ERC20.
 * https://github.com/transmissions11/solmate/blob/bff24e835192470ed38bf15dbed6084c2d723ace/src/tokens/ERC20.sol
 */
contract ERC20Permit2 is IERC165, IERC20Permit2 {
    uint8 public immutable override decimals = 18;

    uint public override totalSupply;
    mapping(address => uint) public override balanceOf;
    mapping(address => mapping(address => uint)) public override allowance;

    bytes32 private constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")
    mapping(address => uint) public override nonces;

    // These members are actually immutable as
    // `_initialize` will only indent to be called once.
    string public override name;
    string public override symbol;
    uint private INITIAL_CHAIN_ID;
    bytes32 private INITIAL_DOMAIN_SEPARATOR;

    function _initialize(string memory _name, string memory _symbol) internal {
        name = _name;
        symbol = _symbol;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
    }

    function supportsInterface(bytes4 interfaceID) external pure override returns (bool) {
        return
            interfaceID == this.supportsInterface.selector || // ERC-165
            interfaceID == this.permit.selector || // ERC-2612
            interfaceID == this.permit2.selector; // Permit2
    }

    function DOMAIN_SEPARATOR() public view override returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
    }

    function _computeDomainSeparator() private view returns (bytes32) {
        return keccak256(
            abi.encode(
                // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
                0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,
                keccak256(bytes(name)),
                // keccak256(bytes("1"))
                0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6,
                block.chainid,
                address(this)
            )
        );
    }

    function _approve(address _owner, address _spender, uint _amount) private {
        allowance[_owner][_spender] = _amount;
        emit Approval(_owner, _spender, _amount);
    }

    function approve(address _spender, uint _amount) public override returns (bool) {
        _approve(msg.sender, _spender, _amount);
        return true;
    }

    function transfer(address _to, uint _amount) public override returns (bool) {
        balanceOf[msg.sender] -= _amount;

        // Cannot overflow because the sum of all user balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[_to] += _amount;
        }

        emit Transfer(msg.sender, _to, _amount);
        return true;
    }

    function transferFrom(address _from, address _to, uint _amount) public override returns (bool) {
        uint256 _allowed = allowance[_from][msg.sender]; // Saves gas for limited approvals.
        if (_allowed != type(uint).max) {
            allowance[_from][msg.sender] = _allowed - _amount;
        }

        balanceOf[_from] -= _amount;
        // Cannot overflow because the sum of all user balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[_to] += _amount;
        }

        emit Transfer(_from, _to, _amount);
        return true;
    }

    function _mint(address _to, uint _amount) internal {
        totalSupply += _amount;

        // Cannot overflow because the sum of all user balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[_to] += _amount;
        }

        emit Transfer(address(0), _to, _amount);
    }

    function _burn(address _from, uint _amount) internal {
        balanceOf[_from] -= _amount;

        // Cannot underflow because a user's balance will never be larger than the total supply.
        unchecked {
            totalSupply -= _amount;
        }

        emit Transfer(_from, address(0), _amount);
    }

    modifier ensures(uint _deadline) {
        // solhint-disable-next-line not-rely-on-time
        if (block.timestamp > _deadline) {
            revert Expired();
        }
        _;
    }

    function _permitHash(
        address _owner,
        address _spender,
        uint _amount,
        uint _deadline
    ) private returns (bytes32) {
        return keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR(),
                keccak256(abi.encode(PERMIT_TYPEHASH, _owner, _spender, _amount, nonces[_owner]++, _deadline))
            )
        );
    }

    function permit(
        address _owner,
        address _spender,
        uint _amount,
        uint _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) public override ensures(_deadline) {
        bytes32 _hash = _permitHash(_owner, _spender, _amount, _deadline);
        address _recoveredAddress = ecrecover(_hash, _v, _r, _s);

        if (_recoveredAddress != _owner) {
            revert InvalidSignature();
        }
        if (_recoveredAddress == address(0)) {
            revert InvalidSignature();
        }

        _approve(_owner, _spender, _amount);
    }

    function permit2(
        address _owner,
        address _spender,
        uint _amount,
        uint _deadline,
        bytes calldata _signature
    ) public override ensures(_deadline) {
        bytes32 _hash = _permitHash(_owner, _spender, _amount, _deadline);

        if (!SignatureChecker.isValidSignatureNow(_owner, _hash, _signature)) {
            revert InvalidSignature();
        }

        _approve(_owner, _spender, _amount);
    }
}

File 24 of 29 : Math.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

/// @dev Math functions.
/// @dev Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library Math {

    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    function geometricMean(uint a, uint b) internal pure returns (uint) {
        return Math.sqrt(a * b);
    }

    /// @notice Compares a and b and returns 'true' if the difference between a and b
    /// is less than 1 or equal to each other.
    /// @param a uint256 to compare with.
    /// @param b uint256 to compare with.
    function within1(uint256 a, uint256 b) internal pure returns (bool) {
        unchecked {
            if (a > b) {
                return a - b <= 1;
            }
            return b - a <= 1;
        }
    }

    /// @dev Returns the square root of `x`.
    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // Let `y = x / 2**r`.
            // We check `y >= 2**(k + 8)` but shift right by `k` bits
            // each branch to ensure that if `x >= 256`, then `y >= 256`.
            let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
            r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
            r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
            r := or(r, shl(4, lt(0xffffff, shr(r, x))))
            z := shl(shr(1, r), z)

            // Goal was to get `z*z*y` within a small factor of `x`. More iterations could
            // get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
            // We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
            // That's not possible if `x < 256` but we can just verify those cases exhaustively.

            // Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
            // Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
            // Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.

            // For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
            // is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
            // with largest error when `s = 1` and when `s = 256` or `1/256`.

            // Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
            // Then we can estimate `sqrt(y)` using
            // `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.

            // There is no overflow risk here since `y < 2**136` after the first branch above.
            z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If `x+1` is a perfect square, the Babylonian method cycles between
            // `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    // Mul Div

    /// @dev Rounded down.
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    /// @dev Rounded down.
    /// This function assumes that `x` is not zero, and must be checked externally.
    function mulDivUnsafeFirst(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x * y) / x == y)
            if iszero(and(iszero(iszero(denominator)), eq(div(z, x), y))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    /// @dev Rounded down.
    /// This function assumes that `denominator` is not zero, and must be checked externally.
    function mulDivUnsafeLast(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(x == 0 || (x * y) / x == y)
            if iszero(or(iszero(x), eq(div(z, x), y))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    /// @dev Rounded down.
    /// This function assumes that both `x` and `denominator` are not zero, and must be checked externally.
    function mulDivUnsafeFirstLast(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require((x * y) / x == y)
            if iszero(eq(div(z, x), y)) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    // Mul

    /// @dev Optimized safe multiplication operation for minimal gas cost.
    /// Equivalent to *
    function mul(
        uint256 x,
        uint256 y
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(x == 0 || (x * y) / x == y)
            if iszero(or(iszero(x), eq(div(z, x), y))) {
                revert(0, 0)
            }
        }
    }

    /// @dev Optimized unsafe multiplication operation for minimal gas cost.
    /// This function assumes that `x` is not zero, and must be checked externally.
    function mulUnsafeFirst(
        uint256 x,
        uint256 y
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require((x * y) / x == y)
            if iszero(eq(div(z, x), y)) {
                revert(0, 0)
            }
        }
    }

    // Div

    /// @dev Optimized safe division operation for minimal gas cost.
    /// Equivalent to /
    function div(
        uint256 x,
        uint256 y
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x / y in z for now.
            z := div(x, y)

            // Equivalent to require(y != 0)
            if iszero(y) {
                revert(0, 0)
            }
        }
    }

    /// @dev Optimized unsafe division operation for minimal gas cost.
    /// Division by 0 will not reverts and returns 0, and must be checked externally.
    function divUnsafeLast(
        uint256 x,
        uint256 y
    ) internal pure returns (uint256 z) {
        assembly {
            z := div(x, y)
        }
    }
}

File 25 of 29 : MetadataHelper.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

library MetadataHelper {
    /**
     * @dev Returns symbol of the token.
     *
     * @param token The address of a ERC20 token.
     *
     * Return boolean indicating the status and the symbol as string;
     *
     * NOTE: Symbol is not the standard interface and some tokens may not support it.
     * Calling against these tokens will not success, with an empty result.
     */
    function getSymbol(address token) internal view returns (bool, string memory) {
        // bytes4(keccak256(bytes("symbol()")))
        (bool success, bytes memory returndata) = token.staticcall(abi.encodeWithSelector(0x95d89b41));
        if (success) {
            return (true, abi.decode(returndata, (string)));
        } else {
            return (false, "");
        }
    }
}

File 26 of 29 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

File 27 of 29 : SignatureChecker.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

import "./ECDSA.sol";

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Gnosis Safe.
 *
 * Based on OpenZeppelin's SignatureChecker library.
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/561d1061fc568f04c7a65853538e834a889751e8/contracts/utils/cryptography/SignatureChecker.sol
 */
library SignatureChecker {

    bytes4 constant internal MAGICVALUE = 0x1626ba7e; // bytes4(keccak256("isValidSignature(bytes32,bytes)")

    /** 
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (address recovered) = ECDSA.recover(hash, signature);
        if (recovered == signer) {
            if (recovered != address(0)) {
                return true;
            }
        }

        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeWithSelector(MAGICVALUE, hash, signature)
        );
        return (
            success &&
            result.length == 32 &&
            abi.decode(result, (bytes32)) == bytes32(MAGICVALUE)
        );
    }
}

File 28 of 29 : BasePoolFactory.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

import "../interfaces/factory/IBasePoolFactory.sol";
import "../interfaces/master/IPoolMaster.sol";

error InvalidTokens();

abstract contract BasePoolFactory is IBasePoolFactory {
    /// @dev The pool master that control fees and registry.
    address public immutable master;

    /// @dev Pools by its two pool tokens.
    mapping(address => mapping(address => address)) public override getPool;

    bytes internal cachedDeployData;

    constructor(address _master) {
        master = _master;
    }

    function getDeployData() external view override returns (bytes memory deployData) {
        deployData = cachedDeployData;
    }

    function getSwapFee(
        address pool,
        address sender,
        address tokenIn,
        address tokenOut,
        bytes calldata data
    ) external view override returns (uint24 swapFee) {
        swapFee = IPoolMaster(master).getSwapFee(pool, sender, tokenIn, tokenOut, data);
    }

    function createPool(bytes calldata data) external override returns (address pool) {
        (address tokenA, address tokenB) = abi.decode(data, (address, address));

        // Perform safety checks.
        if (tokenA == tokenB) {
            revert InvalidTokens();
        }

        // Sort tokens.
        if (tokenB < tokenA) {
            (tokenA, tokenB) = (tokenB, tokenA);
        }
        if (tokenA == address(0)) {
            revert InvalidTokens();
        }

        // Underlying implementation to deploy the pools and register them.
        pool = _createPool(tokenA, tokenB);

        // Populate mapping in both directions.
        // Not necessary as existence of the master, but keep them for better compatibility.
        getPool[tokenA][tokenB] = pool;
        getPool[tokenB][tokenA] = pool;

        emit PoolCreated(tokenA, tokenB, pool);
    }

    function _createPool(address tokenA, address tokenB) internal virtual returns (address) {
    }
}

File 29 of 29 : SyncSwapClassicPool.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;

import "../../libraries/Math.sol";
import "../../libraries/ERC20Permit2.sol";
import "../../libraries/MetadataHelper.sol";
import "../../libraries/ReentrancyGuard.sol";

import "../../interfaces/ICallback.sol";
import "../../interfaces/vault/IVault.sol";
import "../../interfaces/pool/IClassicPool.sol";
import "../../interfaces/master/IPoolMaster.sol";
import "../../interfaces/master/IFeeRecipient.sol";
import "../../interfaces/factory/IPoolFactory.sol";

error Overflow();
error InsufficientLiquidityMinted();

contract SyncSwapClassicPool is IClassicPool, ERC20Permit2, ReentrancyGuard {
    using Math for uint;

    uint private constant MINIMUM_LIQUIDITY = 1000;
    uint private constant MAX_FEE = 1e5; /// @dev 100%.

    /// @dev Pool type `1` for classic pools.
    uint16 public constant override poolType = 1;

    address public immutable override master;
    address public immutable override vault;

    address public immutable override token0;
    address public immutable override token1;

    /// @dev Pool reserve of each pool token as of immediately after the most recent balance event.
    /// The value is used to measure growth in invariant on mints and input tokens on swaps.
    uint public override reserve0;
    uint public override reserve1;

    /// @dev Invariant of the pool as of immediately after the most recent liquidity event.
    /// The value is used to measure growth in invariant when protocol fee is enabled,
    /// and will be reset to zero if protocol fee is disabled.
    uint public override invariantLast;

    /// @dev Factory must ensures that the parameters are valid.
    constructor() {
        (bytes memory _deployData) = IPoolFactory(msg.sender).getDeployData();
        (address _token0, address _token1) = abi.decode(_deployData, (address, address));
        address _master = IPoolFactory(msg.sender).master();

        master = _master;
        vault = IPoolMaster(_master).vault();
        (token0, token1) = (_token0, _token1);

        // try to set symbols for the LP token
        (bool _success0, string memory _symbol0) = MetadataHelper.getSymbol(_token0);
        (bool _success1, string memory _symbol1) = MetadataHelper.getSymbol(_token1);
        if (_success0 && _success1) {
            _initialize(
                string(abi.encodePacked("SyncSwap ", _symbol0, "/", _symbol1, " Classic LP")),
                string(abi.encodePacked(_symbol0, "/", _symbol1, " cSLP"))
            );
        } else {
            _initialize(
                "SyncSwap Classic LP",
                "cSLP"
            );
        }
    }

    function getAssets() external view override returns (address[] memory assets) {
        assets = new address[](2);
        assets[0] = token0;
        assets[1] = token1;
    }

    /// @dev Returns the verified sender address otherwise `address(0)`.
    function _getVerifiedSender(address _sender) private view returns (address) {
        if (_sender != address(0)) {
            if (_sender != msg.sender) {
                if (!IPoolMaster(master).isForwarder(msg.sender)) {
                    // The sender from non-forwarder is invalid.
                    return address(0);
                }
            }
        }
        return _sender;
    }

    /// @dev Mints LP tokens - should be called via the router after transferring pool tokens.
    /// The router should ensure that sufficient LP tokens are minted.
    function mint(
        bytes calldata _data,
        address _sender,
        address _callback,
        bytes calldata _callbackData
    ) external override nonReentrant returns (uint) {
        ICallback.BaseMintCallbackParams memory params;

        params.to = abi.decode(_data, (address));
        (params.reserve0, params.reserve1) = (reserve0, reserve1);
        (params.balance0, params.balance1) = _balances();

        params.newInvariant = _computeInvariant(params.balance0, params.balance1);
        params.amount0 = params.balance0 - params.reserve0;
        params.amount1 = params.balance1 - params.reserve1;
        //require(_amount0 != 0 && _amount1 != 0);

        // Gets swap fee for the sender.
        _sender = _getVerifiedSender(_sender);
        uint _amount1Optimal = params.reserve0 == 0 ? 0 : Math.divUnsafeLast((params.amount0 * params.reserve1), params.reserve0);
        bool _swap0For1 = params.amount1 < _amount1Optimal;
        if (_swap0For1) {
            params.swapFee = _getSwapFee(_sender, token0, token1);
        } else {
            params.swapFee = _getSwapFee(_sender, token1, token0);
        }

        // Adds mint fee to reserves (applies to invariant increase) if unbalanced.
        (params.fee0, params.fee1) = _unbalancedMintFee(params.swapFee, params.amount0, params.amount1, _amount1Optimal, params.reserve0, params.reserve1);
        params.reserve0 += params.fee0;
        params.reserve1 += params.fee1;

        // Calculates old invariant (where unbalanced fee added to) and, mint protocol fee if any.
        params.oldInvariant = _computeInvariant(params.reserve0, params.reserve1);
        bool _feeOn;
        (_feeOn, params.totalSupply) = _mintProtocolFee(0, 0, params.oldInvariant);

        if (params.totalSupply == 0) {
            params.liquidity = params.newInvariant - MINIMUM_LIQUIDITY;
            _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock on first mint.
        } else {
            // Calculates liquidity proportional to invariant growth.
            params.liquidity = ((params.newInvariant - params.oldInvariant) * params.totalSupply) / params.oldInvariant;
        }

        // Mints liquidity for recipient.
        if (params.liquidity == 0) {
            revert InsufficientLiquidityMinted();
        }
        _mint(params.to, params.liquidity);

        // Calls callback with data.
        if (_callback != address(0)) {
            // Fills additional values for callback params.
            params.sender = _sender;
            params.callbackData = _callbackData;

            ICallback(_callback).syncSwapBaseMintCallback(params);
        }

        // Updates reserves and last invariant with new balances.
        _updateReserves(params.balance0, params.balance1);
        if (_feeOn) {
            invariantLast = params.newInvariant;
        }

        emit Mint(msg.sender, params.amount0, params.amount1, params.liquidity, params.to);

        return params.liquidity;
    }

    /// @dev Burns LP tokens sent to this contract.
    /// The router should ensure that sufficient pool tokens are received.
    function burn(
        bytes calldata _data,
        address _sender,
        address _callback,
        bytes calldata _callbackData
    ) external override nonReentrant returns (TokenAmount[] memory _amounts) {
        ICallback.BaseBurnCallbackParams memory params;

        (params.to, params.withdrawMode) = abi.decode(_data, (address, uint8));
        (params.balance0, params.balance1) = _balances();
        params.liquidity = balanceOf[address(this)];

        // Mints protocol fee if any.
        // Note `_mintProtocolFee` here will checks overflow.
        bool _feeOn;
        (_feeOn, params.totalSupply) = _mintProtocolFee(params.balance0, params.balance1, 0);

        // Calculates amounts of pool tokens proportional to balances.
        require(params.totalSupply != 0);
        params.amount0 = Math.divUnsafeLast(params.liquidity * params.balance0, params.totalSupply);
        params.amount1 = Math.divUnsafeLast(params.liquidity * params.balance1, params.totalSupply);
        //require(_amount0 != 0 || _amount1 != 0);

        // Burns liquidity and transfers pool tokens.
        _burn(address(this), params.liquidity);
        _transferTokens(token0, params.to, params.amount0, params.withdrawMode);
        _transferTokens(token1, params.to, params.amount1, params.withdrawMode);

        // Updates balances.
        /// @dev Cannot underflow because amounts are lesser figures derived from balances.
        unchecked {
            params.balance0 -= params.amount0;
            params.balance1 -= params.amount1;
        }

        // Calls callback with data.
        // Note reserves are not updated at this point to allow read the old values.
        if (_callback != address(0)) {
            // Fills additional values for callback params.
            params.sender = _getVerifiedSender(_sender);
            params.callbackData = _callbackData;

            ICallback(_callback).syncSwapBaseBurnCallback(params);
        }

        // Updates reserves and last invariant with up-to-date balances (after transfers).
        _updateReserves(params.balance0, params.balance1);
        if (_feeOn) {
            invariantLast = _computeInvariant(params.balance0, params.balance1);
        }

        _amounts = new TokenAmount[](2);
        _amounts[0] = TokenAmount(token0, params.amount0);
        _amounts[1] = TokenAmount(token1, params.amount1);

        emit Burn(msg.sender, params.amount0, params.amount1, params.liquidity, params.to);
    }

    /// @dev Burns LP tokens sent to this contract and swaps one of the output tokens for another
    /// - i.e., the user gets a single token out by burning LP tokens.
    /// The router should ensure that sufficient pool tokens are received.
    function burnSingle(
        bytes calldata _data,
        address _sender,
        address _callback,
        bytes calldata _callbackData
    ) external override nonReentrant returns (TokenAmount memory _tokenAmount) {
        ICallback.BaseBurnSingleCallbackParams memory params;

        (params.tokenOut, params.to, params.withdrawMode) = abi.decode(_data, (address, address, uint8));
        (params.balance0, params.balance1) = _balances();
        params.liquidity = balanceOf[address(this)];

        // Mints protocol fee if any.
        // Note `_mintProtocolFee` here will checks overflow.
        bool _feeOn;
        (_feeOn, params.totalSupply) = _mintProtocolFee(params.balance0, params.balance1, 0);

        // Calculates amounts of pool tokens proportional to balances.
        require(params.totalSupply != 0);
        params.amount0 = Math.divUnsafeLast(params.liquidity * params.balance0, params.totalSupply);
        params.amount1 = Math.divUnsafeLast(params.liquidity * params.balance1, params.totalSupply);

        // Burns liquidity.
        _burn(address(this), params.liquidity);

        // Gets swap fee for the sender.
        _sender = _getVerifiedSender(_sender);

        // Swaps one token for another, transfers desired tokens, and update context values.
        /// @dev Calculate `amountOut` as if the user first withdrew balanced liquidity and then swapped from one token for another.
        if (params.tokenOut == token1) {
            // Swaps `token0` for `token1`.
            params.swapFee = _getSwapFee(_sender, token0, token1);

            params.tokenIn = token0;
            (params.amountSwapped, params.feeIn) = _getAmountOut(
                params.swapFee, params.amount0, params.balance0 - params.amount0, params.balance1 - params.amount1, true
            );
            params.amount1 += params.amountSwapped;

            _transferTokens(token1, params.to, params.amount1, params.withdrawMode);
            params.amountOut = params.amount1;
            params.amount0 = 0;
            params.balance1 -= params.amount1;
        } else {
            // Swaps `token1` for `token0`.
            require(params.tokenOut == token0);
            params.swapFee = _getSwapFee(_sender, token1, token0);

            params.tokenIn = token1;
            (params.amountSwapped, params.feeIn) = _getAmountOut(
                params.swapFee, params.amount1, params.balance0 - params.amount0, params.balance1 - params.amount1, false
            );
            params.amount0 += params.amountSwapped;

            _transferTokens(token0, params.to, params.amount0, params.withdrawMode);
            params.amountOut = params.amount0;
            params.amount1 = 0;
            params.balance0 -= params.amount0;
        }

        // Calls callback with data.
        // Note reserves are not updated at this point to allow read the old values.
        if (_callback != address(0)) {
            // Fills additional values for callback params.
            params.sender = _sender;
            params.callbackData = _callbackData;

            /// @dev Note the `tokenOut` parameter can be decided by the caller, and the correctness is not guaranteed.
            /// Additional checks MUST be performed in callback to ensure the `tokenOut` is one of the pools tokens if the sender
            /// is not a trusted source to avoid potential issues.
            ICallback(_callback).syncSwapBaseBurnSingleCallback(params);
        }

        // Update reserves and last invariant with up-to-date balances (updated above).
        _updateReserves(params.balance0, params.balance1);
        if (_feeOn) {
            invariantLast = _computeInvariant(params.balance0, params.balance1);
        }

        _tokenAmount = TokenAmount(params.tokenOut, params.amountOut);

        emit Burn(msg.sender, params.amount0, params.amount1, params.liquidity, params.to);
    }

    /// @dev Swaps one token for another - should be called via the router after transferring input tokens.
    /// The router should ensure that sufficient output tokens are received.
    function swap(
        bytes calldata _data,
        address _sender,
        address _callback,
        bytes calldata _callbackData
    ) external override nonReentrant returns (TokenAmount memory _tokenAmount) {
        ICallback.BaseSwapCallbackParams memory params;

        (params.tokenIn, params.to, params.withdrawMode) = abi.decode(_data, (address, address, uint8));
        (params.reserve0, params.reserve1) = (reserve0, reserve1);
        (params.balance0, params.balance1) = _balances();

        // Gets swap fee for the sender.
        _sender = _getVerifiedSender(_sender);

        // Calculates output amount, update context values and emit event.
        if (params.tokenIn == token0) {
            params.swapFee = _getSwapFee(_sender, token0, token1);

            params.tokenOut = token1;
            params.amountIn = params.balance0 - params.reserve0;

            (params.amountOut, params.feeIn) = _getAmountOut(params.swapFee, params.amountIn, params.reserve0, params.reserve1, true);
            params.balance1 -= params.amountOut;

            emit Swap(msg.sender, params.amountIn, 0, 0, params.amountOut, params.to);
        } else {
            require(params.tokenIn == token1);
            params.swapFee = _getSwapFee(_sender, token1, token0);

            params.tokenOut = token0;
            params.amountIn = params.balance1 - params.reserve1;

            (params.amountOut, params.feeIn) = _getAmountOut(params.swapFee, params.amountIn, params.reserve0, params.reserve1, false);
            params.balance0 -= params.amountOut;

            emit Swap(msg.sender, 0, params.amountIn, params.amountOut, 0, params.to);
        }

        // Checks overflow.
        if (params.balance0 > type(uint128).max) {
            revert Overflow();
        }
        if (params.balance1 > type(uint128).max) {
            revert Overflow();
        }

        // Transfers output tokens.
        _transferTokens(params.tokenOut, params.to, params.amountOut, params.withdrawMode);

        // Calls callback with data.
        if (_callback != address(0)) {
            // Fills additional values for callback params.
            params.sender = _sender;
            params.callbackData = _callbackData;

            /// @dev Note the `tokenIn` parameter can be decided by the caller, and the correctness is not guaranteed.
            /// Additional checks MUST be performed in callback to ensure the `tokenIn` is one of the pools tokens if the sender
            /// is not a trusted source to avoid potential issues.
            ICallback(_callback).syncSwapBaseSwapCallback(params);
        }

        // Updates reserves with up-to-date balances (updated above).
        _updateReserves(params.balance0, params.balance1);

        _tokenAmount.token = params.tokenOut;
        _tokenAmount.amount = params.amountOut;
    }

    function _getSwapFee(address _sender, address _tokenIn, address _tokenOut) private view returns (uint24 _swapFee) {
        _swapFee = getSwapFee(_sender, _tokenIn, _tokenOut, "");
    }

    /// @dev This function doesn't check the forwarder.
    function getSwapFee(address _sender, address _tokenIn, address _tokenOut, bytes memory data) public view override returns (uint24 _swapFee) {
        _swapFee = IPoolMaster(master).getSwapFee(address(this), _sender, _tokenIn, _tokenOut, data);
    }

    function getProtocolFee() public view override returns (uint24 _protocolFee) {
        _protocolFee = IPoolMaster(master).getProtocolFee(address(this));
    }

    function _updateReserves(uint _balance0, uint _balance1) private {
        (reserve0, reserve1) = (_balance0, _balance1);
        emit Sync(_balance0, _balance1);
    }

    function _transferTokens(address token, address to, uint amount, uint8 withdrawMode) private {
        if (withdrawMode == 0) {
            IVault(vault).transfer(token, to, amount);
        } else {
            IVault(vault).withdrawAlternative(token, to, amount, withdrawMode);
        }
    }

    function _balances() private view returns (uint balance0, uint balance1) {
        balance0 = IVault(vault).balanceOf(token0, address(this));
        balance1 = IVault(vault).balanceOf(token1, address(this));
    }

    /// @dev This fee is charged to cover for the swap fee when users adding unbalanced liquidity.
    function _unbalancedMintFee(
        uint _swapFee,
        uint _amount0,
        uint _amount1,
        uint _amount1Optimal,
        uint _reserve0,
        uint _reserve1
    ) private pure returns (uint _token0Fee, uint _token1Fee) {
        if (_reserve0 == 0) {
            return (0, 0);
        }
        if (_amount1 >= _amount1Optimal) {
            _token1Fee = Math.divUnsafeLast((_swapFee * (_amount1 - _amount1Optimal)), (2 * MAX_FEE));
        } else {
            uint _amount0Optimal = (_amount1 * _reserve0) / _reserve1;
            _token0Fee = Math.divUnsafeLast((_swapFee * (_amount0 - _amount0Optimal)), (2 * MAX_FEE));
        }
    }

    function _mintProtocolFee(uint _reserve0, uint _reserve1, uint _invariant) private returns (bool _feeOn, uint _totalSupply) {
        _totalSupply = totalSupply;

        address _feeRecipient = IPoolMaster(master).getFeeRecipient();
        _feeOn = (_feeRecipient != address(0));

        uint _invariantLast = invariantLast;
        if (_invariantLast != 0) {
            if (_feeOn) {
                if (_invariant == 0) {
                    _invariant = _computeInvariant(_reserve0, _reserve1);
                }

                if (_invariant > _invariantLast) {
                    /// @dev Mints `protocolFee` % of growth in liquidity (invariant).
                    uint _protocolFee = getProtocolFee();
                    uint _numerator = _totalSupply * (_invariant - _invariantLast) * _protocolFee;
                    uint _denominator = (MAX_FEE - _protocolFee) * _invariant + _protocolFee * _invariantLast;
                    uint _liquidity = _numerator / _denominator;

                    if (_liquidity != 0) {
                        _mint(_feeRecipient, _liquidity);

                        // Notifies the fee recipient.
                        IFeeRecipient(_feeRecipient).notifyFees(1, address(this), _liquidity, _protocolFee, "");

                        _totalSupply += _liquidity; // update cached value.
                    }
                }
            } else {
                /// @dev Resets last invariant to clear measured growth if protocol fee is not enabled.
                invariantLast = 0;
            }
        }
    }

    function getReserves() external view override returns (uint _reserve0, uint _reserve1) {
        (_reserve0, _reserve1) = (reserve0, reserve1);
    }

    function getAmountOut(address _tokenIn, uint _amountIn, address _sender) external view override returns (uint _amountOut) {
        (uint _reserve0, uint _reserve1) = (reserve0, reserve1);
        bool _swap0For1 = _tokenIn == token0;
        address _tokenOut = _swap0For1 ? token1 : token0;
        (_amountOut,) = _getAmountOut(_getSwapFee(_sender, _tokenIn, _tokenOut), _amountIn, _reserve0, _reserve1, _swap0For1);
    }

    function getAmountIn(address _tokenOut, uint _amountOut, address _sender) external view override returns (uint _amountIn) {
        (uint _reserve0, uint _reserve1) = (reserve0, reserve1);
        bool _swap1For0 = _tokenOut == token0;
        address _tokenIn = _swap1For0 ? token1 : token0;
        _amountIn = _getAmountIn(_getSwapFee(_sender, _tokenIn, _tokenOut), _amountOut, _reserve0, _reserve1, _swap1For0);
    }

    function _getAmountOut(
        uint _swapFee,
        uint _amountIn,
        uint _reserve0,
        uint _reserve1,
        bool _token0In
    ) private pure returns (uint _dy, uint _feeIn) {
        if (_amountIn == 0) {
            _dy = 0;
        } else {
            uint _amountInWithFee = _amountIn * (MAX_FEE - _swapFee);
            _feeIn = Math.divUnsafeLast(_amountIn * _swapFee, MAX_FEE);

            if (_token0In) {
                _dy = (_amountInWithFee * _reserve1) / (_reserve0 * MAX_FEE + _amountInWithFee);
            } else {
                _dy = (_amountInWithFee * _reserve0) / (_reserve1 * MAX_FEE + _amountInWithFee);
            }
        }
    }

    function _getAmountIn(
        uint _swapFee,
        uint _amountOut,
        uint _reserve0,
        uint _reserve1,
        bool _token0Out
    ) private pure returns (uint _dx) {
        if (_amountOut == 0) {
            _dx = 0;
        } else {
            if (_token0Out) {
                _dx = (_reserve1 * _amountOut * MAX_FEE) / ((_reserve0 - _amountOut) * (MAX_FEE - _swapFee)) + 1;
            } else {
                _dx = (_reserve0 * _amountOut * MAX_FEE) / ((_reserve1 - _amountOut) * (MAX_FEE - _swapFee)) + 1;
            }
        }
    }

    function _computeInvariant(uint _reserve0, uint _reserve1) private pure returns (uint _invariant) {
        if (_reserve0 > type(uint128).max) {
            revert Overflow();
        }
        if (_reserve1 > type(uint128).max) {
            revert Overflow();
        }
        _invariant = (_reserve0 * _reserve1).sqrt();
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200,
    "details": {
      "yul": false
    }
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_master","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidTokens","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token0","type":"address"},{"indexed":true,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"}],"name":"PoolCreated","type":"event"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"createPool","outputs":[{"internalType":"address","name":"pool","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getDeployData","outputs":[{"internalType":"bytes","name":"deployData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"getSwapFee","outputs":[{"internalType":"uint24","name":"swapFee","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"master","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60a060405234801561001057600080fd5b5060405161599a38038061599a83398101604081905261002f91610075565b6001600160a01b031660805261009e565b60006001600160a01b0382165b92915050565b61005c81610040565b811461006757600080fd5b50565b805161004d81610053565b60006020828403121561008a5761008a600080fd5b6000610096848461006a565b949350505050565b6080516158d36100c76000396000818161010b0152818161027e015261051c01526158d36000f3fe60806040523480156200001157600080fd5b50600436106200005e5760003560e01c806313b8683f14620000635780634625a94d1462000092578063531aa03e14620000b8578063d039f62214620000ec578063ee97f7f31462000105575b600080fd5b6200007a62000074366004620005fa565b6200012d565b6040516200008991906200066c565b60405180910390f35b620000a9620000a3366004620006a3565b62000264565b60405162000089919062000753565b6200007a620000c936600462000763565b60006020818152928152604080822090935290815220546001600160a01b031681565b620000f66200030e565b60405162000089919062000810565b6200007a7f000000000000000000000000000000000000000000000000000000000000000081565b600080806200013f8486018662000763565b91509150806001600160a01b0316826001600160a01b03160362000176576040516333910aef60e11b815260040160405180910390fd5b816001600160a01b0316816001600160a01b031610156200019357905b6001600160a01b038216620001bb576040516333910aef60e11b815260040160405180910390fd5b620001c78282620003a8565b6001600160a01b0380841660008181526020818152604080832087861680855290835281842080549688166001600160a01b03199788168117909155848452828520868652909352928190208054909516909117909355915192955090917f9c5d829b9b23efc461f9aeef91979ec04bb903feb3bee4f26d22114abfc7335b90620002549087906200066c565b60405180910390a3505092915050565b604051634625a94d60e01b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634625a94d90620002bf908a908a908a908a908a908a906004016200085c565b602060405180830381865afa158015620002dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003039190620008d3565b979650505050505050565b6060600180546200031f9062000916565b80601f01602080910402602001604051908101604052809291908181526020018280546200034d9062000916565b80156200039e5780601f1062000372576101008083540402835291602001916200039e565b820191906000526020600020905b8154815290600101906020018083116200038057829003601f168201915b5050505050905090565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190620003d99030906004016200066c565b602060405180830381865afa158015620003f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200041d91906200095a565b506040516370a0823160e01b81526001600160a01b038316906370a08231906200044c9030906004016200066c565b602060405180830381865afa1580156200046a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200049091906200095a565b5060008383604051602001620004a89291906200097f565b60408051601f1981840301815291905290506001620004c8828262000a6b565b50805160208201206040518190620004e09062000594565b8190604051809103906000f590508015801562000501573d6000803e3d6000fd5b5060405163784198d960e01b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063784198d99062000558908690600190879060040162000b54565b600060405180830381600087803b1580156200057357600080fd5b505af115801562000588573d6000803e3d6000fd5b50505050505092915050565b614d0d8062000b9183390190565b60008083601f840112620005b957620005b9600080fd5b50813567ffffffffffffffff811115620005d657620005d6600080fd5b602083019150836001820283011115620005f357620005f3600080fd5b9250929050565b60008060208385031215620006125762000612600080fd5b823567ffffffffffffffff8111156200062e576200062e600080fd5b6200063c85828601620005a2565b92509250509250929050565b60006001600160a01b0382165b92915050565b620006668162000648565b82525050565b602081016200065582846200065b565b620006878162000648565b81146200069357600080fd5b50565b803562000655816200067c565b60008060008060008060a08789031215620006c157620006c1600080fd5b6000620006cf898962000696565b9650506020620006e289828a0162000696565b9550506040620006f589828a0162000696565b94505060606200070889828a0162000696565b935050608087013567ffffffffffffffff8111156200072a576200072a600080fd5b6200073889828a01620005a2565b92509250509295509295509295565b62ffffff811662000666565b6020810162000655828462000747565b600080604083850312156200077b576200077b600080fd5b600062000789858562000696565b92505060206200079c8582860162000696565b9150509250929050565b60005b83811015620007c3578181015183820152602001620007a9565b83811115620007d3576000848401525b50505050565b6000620007e4825190565b808452602084019350620007fd818560208601620007a6565b601f19601f8201165b9093019392505050565b60208082528101620008238184620007d9565b9392505050565b82818337506000910152565b81835260006020840193506200084e8385846200082a565b601f19601f84011662000806565b60a081016200086c82896200065b565b6200087b60208301886200065b565b6200088a60408301876200065b565b6200089960608301866200065b565b8181036080830152620008ae81848662000836565b98975050505050505050565b62ffffff811662000687565b80516200065581620008ba565b600060208284031215620008ea57620008ea600080fd5b6000620008f88484620008c6565b949350505050565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200092b57607f821691505b60208210810362000940576200094062000900565b50919050565b8062000687565b8051620006558162000946565b600060208284031215620009715762000971600080fd5b6000620008f884846200094d565b604081016200098f82856200065b565b6200082360208301846200065b565b634e487b7160e01b600052604160045260246000fd5b600062000655620009c28381565b90565b620009d083620009b4565b81546008840282811b60001990911b908116901990911617825550505050565b6000620009ff818484620009c5565b505050565b8181101562000a235762000a1a600082620009f0565b60010162000a04565b5050565b601f821115620009ff576000818152602090206020601f8501048101602085101562000a505750805b62000a646020601f86010483018262000a04565b5050505050565b815167ffffffffffffffff81111562000a885762000a886200099e565b62000a94825462000916565b62000aa182828562000a27565b6020601f83116001811462000ad8576000841562000abf5750858201515b600019600886021c198116600286021786555062000b34565b600085815260208120601f198616915b8281101562000b0a578885015182556020948501946001909201910162000ae8565b8683101562000b275784890151600019601f89166008021c191682555b6001600288020188555050505b505050505050565b600061ffff821662000655565b620006668162000b3c565b6060810162000b6482866200065b565b62000b73602083018562000b49565b818103604083015262000b878184620007d9565b9594505050505056fe61012060405260126080523480156200001757600080fd5b5060016008819055506000336001600160a01b031663d039f6226040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000061573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200008b919081019062000597565b905060008082806020019051810190620000a6919062000611565b915091506000336001600160a01b031663ee97f7f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000111919062000654565b9050806001600160a01b031660a0816001600160a01b031681525050806001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200016c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000192919062000654565b6001600160a01b0390811660c05282811661010052831660e052600080620001c685620002c2602090811b6200210017901c565b91509150600080620001e386620002c260201b620021001760201c565b91509150838015620001f25750815b1562000251576200024b8382604051602001620002119291906200069e565b604051602081830303815290604052848360405160200162000235929190620006f3565b60408051601f198184030181529190526200039a565b620002b4565b620002b46040518060400160405280601381526020017f53796e635377617020436c6173736963204c500000000000000000000000000081525060405180604001604052806004815260200163063534c560e41b8152506200039a60201b60201c565b505050505050505062000a13565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051600091606091839182916001600160a01b038716916200030c9162000730565b600060405180830381855afa9150503d806000811462000349576040519150601f19603f3d011682016040523d82523d6000602084013e6200034e565b606091505b509150915081156200037d5760018180602001905181019062000372919062000597565b935093505050915091565b600060405180602001604052806000815250935093505050915091565b6004620003a8838262000842565b506005620003b7828262000842565b5046600655620003c6620003cd565b6007555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60046040516200040191906200098c565b6040519081900381206200043f92917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69046903090602001620009bd565b60405160208183030381529060405280519060200120905090565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b03821117156200049857620004986200045a565b6040525050565b6000620004ab60405190565b9050620004b9828262000470565b919050565b60006001600160401b03821115620004da57620004da6200045a565b601f19601f83011660200192915050565b60005b8381101562000508578181015183820152602001620004ee565b8381111562000518576000848401525b50505050565b6000620005356200052f84620004be565b6200049f565b905082815260208101848484011115620005525762000552600080fd5b6200055f848285620004eb565b509392505050565b600082601f8301126200057d576200057d600080fd5b81516200058f8482602086016200051e565b949350505050565b600060208284031215620005ae57620005ae600080fd5b81516001600160401b03811115620005c957620005c9600080fd5b6200058f8482850162000567565b60006001600160a01b0382165b92915050565b620005f581620005d7565b81146200060157600080fd5b50565b8051620005e481620005ea565b60008060408385031215620006295762000629600080fd5b600062000637858562000604565b92505060206200064a8582860162000604565b9150509250929050565b6000602082840312156200066b576200066b600080fd5b60006200058f848462000604565b600062000684825190565b62000694818560208601620004eb565b9290920192915050565b68029bcb731a9bbb0b8160bd1b81526009016000620006be828562000679565b602f60f81b81526001019150620006d6828462000679565b6a020436c6173736963204c560ac1b81529150600b82016200058f565b600062000701828562000679565b602f60f81b8152600101915062000719828462000679565b6402063534c560dc1b81529150600582016200058f565b60006200073e828462000679565b9392505050565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200077057607f821691505b60208210810362000785576200078562000745565b50919050565b6000620005e4620007998381565b90565b620007a7836200078b565b81546008840282811b60001990911b908116901990911617825550505050565b6000620007d68184846200079c565b505050565b81811015620007fa57620007f1600082620007c7565b600101620007db565b5050565b601f821115620007d6576000818152602090206020601f85010481016020851015620008275750805b6200083b6020601f860104830182620007db565b5050505050565b81516001600160401b038111156200085e576200085e6200045a565b6200086a82546200075b565b62000877828285620007fe565b6020601f831160018114620008ae5760008415620008955750858201515b600019600886021c19811660028602178655506200090a565b600085815260208120601f198616915b82811015620008e05788850151825560209485019460019092019101620008be565b86831015620008fd5784890151600019601f89166008021c191682555b6001600288020188555050505b505050505050565b6000815462000921816200075b565b6001821680156200093b5760018114620009515762000983565b60ff198316865281151582028601935062000983565b60008581526020902060005b838110156200097b578154888201526001909101906020016200095d565b838801955050505b50505092915050565b60006200073e828462000912565b620009a5816200078b565b82525050565b80620009a5565b620009a581620005d7565b60a08101620009cd82886200099a565b620009dc6020830187620009ab565b620009eb60408301866200099a565b620009fa6060830185620009ab565b62000a096080830184620009b2565b9695505050505050565b60805160a05160c05160e0516101005161418162000b8c6000396000818161042e015281816106fd0152818161073701528181610d4201528181610da401528181610e6801528181610f1401528181610f700152818161130f015281816114da01528181611513015281816115fe01528181611644015281816119fb01528181611db701528181611fa3015281816120b501526122fc015260008181610288015281816106dc0152818161075801528181610d8301528181610ddf01528181610ece01528181610f3501528181610ffd015281816112bb01528181611478015281816114b9015281816116650152818161169e0152818161199f015281816119d501528181611d7e01528181611f43015281816120590152818161208f01526122370152600081816104da01528181612208015281816122cf015281816129ea0152612a71015260008181610493015281816118ff01528181611a5f0152818161249001526125d40152600061030d01526141816000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806370a082311161010f578063b1dd61b6116100a2578063ee97f7f311610071578063ee97f7f31461048e578063f66eab5b146104b5578063fbfa77cf146104d5578063ff9c8ac6146104fc57600080fd5b8063b1dd61b614610414578063d21220a714610429578063d505accf14610450578063dd62ed3e1461046357600080fd5b806395d89b41116100de57806395d89b41146103de578063a287c795146103e6578063a5a41031146103f9578063a9059cbb1461040157600080fd5b806370a082311461036b5780637132bb7f1461038b5780637ecebe001461039e5780638b4c5470146103be57600080fd5b806323b872dd116101875780633644e515116101565780633644e5151461033c578063443cb4bc146103445780635a76f25e1461034d57806367e4ac2c1461035657600080fd5b806323b872dd146102c057806327b0bcea146102d35780632c0198cc146102f3578063313ce5671461030857600080fd5b80630902f1ac116101c35780630902f1ac1461025c578063095ea7b3146102705780630dfe16811461028357806318160ddd146102b757600080fd5b806301ffc9a7146101f557806303e7286a1461021e57806306fdde031461023e57806307f293f714610253575b600080fd5b610208610203366004612ee1565b61050f565b6040516102159190612f0c565b60405180910390f35b61023161022c366004612f91565b610561565b6040516102159190613038565b610246610a1a565b60405161021591906130a4565b610231600b5481565b600954600a546040516102159291906130b5565b61020861027e3660046130e1565b610aa8565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b6040516102159190613127565b61023160005481565b6102086102ce366004613135565b610abe565b6102e66102e1366004612f91565b610b9e565b60405161021591906131a9565b6103066103013660046131b7565b6111d5565b005b61032f7f000000000000000000000000000000000000000000000000000000000000000081565b604051610215919061323b565b61023161127a565b61023160095481565b610231600a5481565b61035e611299565b60405161021591906132a6565b6102316103793660046132b7565b60016020526000908152604090205481565b6102e6610399366004612f91565b611364565b6102316103ac3660046132b7565b60036020526000908152604090205481565b6103d16103cc3660046133d3565b6118e5565b604051610215919061345d565b610246611986565b6102316103f436600461346b565b611993565b6103d1611a45565b61020861040f3660046130e1565b611ad5565b61041c600181565b60405161021591906134bb565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b61030661045e3660046134dd565b611b4a565b61023161047136600461357c565b600260209081526000928352604080842090915290825290205481565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b6104c86104c3366004612f91565b611c3f565b6040516102159190613601565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b61023161050a36600461346b565b61204d565b60006001600160e01b031982166301ffc9a760e01b148061054057506001600160e01b0319821663d505accf60e01b145b8061055b57506001600160e01b03198216630b00663360e21b145b92915050565b600061056b6121d1565b61060260405180610200016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001606081525090565b61060e878901896132b7565b6001600160a01b03166020820152600954600a5460608301526040820152610634612203565b60a083018190526080830182905261064c919061236d565b610140820152604081015160808201516106669190613628565b60c0820152606081015160a082015161067f9190613628565b60e082015261068d86612458565b9550600081604001516000146106c3576106be82606001518360c001516106b4919061363f565b8360400151900490565b6106c6565b60005b60e08301519091508111801561073157610721887f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101c0840152610788565b61077c887f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101c08401525b6107b0836101c0015162ffffff168460c001518560e00151858760400151886060015161253b565b61012085015261010084018190526040840180516107cf90839061365e565b9052506101208301516060840180516107e990839061365e565b90525060408301516060840151610800919061236d565b610160840181905260009061081890829081906125c8565b6101808601819052909150600003610855576103e884610140015161083d9190613628565b6101a085015261085060006103e86127a1565b61088d565b610160840151610180850151610140860151610872908390613628565b61087c919061363f565b610886919061368c565b6101a08501525b836101a001516000036108b357604051633489be7560e21b815260040160405180910390fd5b6108c68460200151856101a001516127a1565b6001600160a01b0388161561097a576001600160a01b0389168452604080516020601f89018190048102820181019092528781529088908890819084018382808284376000920191909152505050506101e0850152604051630204997360e41b81526001600160a01b038916906320499730906109479087906004016137e7565b600060405180830381600087803b15801561096157600080fd5b505af1158015610975573d6000803e3d6000fd5b505050505b61098c84608001518560a001516127fe565b801561099c57610140840151600b555b83602001516001600160a01b0316336001600160a01b03167fa8137fff86647d8a402117b9c5dbda627f721d3773338fb9678c83e54ed390808660c001518760e00151886101a001516040516109f4939291906137f8565b60405180910390a35050506101a001519050610a106001600855565b9695505050505050565b60048054610a2790613836565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5390613836565b8015610aa05780601f10610a7557610100808354040283529160200191610aa0565b820191906000526020600020905b815481529060010190602001808311610a8357829003601f168201915b505050505081565b6000610ab5338484612846565b50600192915050565b6001600160a01b03831660009081526002602090815260408083203384529091528120546000198114610b1a57610af58382613628565b6001600160a01b03861660009081526002602090815260408083203384529091529020555b6001600160a01b03851660009081526001602052604081208054859290610b42908490613628565b90915550506001600160a01b038085166000818152600160205260409081902080548701905551909187169060008051602061412c83398151915290610b89908790613038565b60405180910390a360019150505b9392505050565b6040805180820190915260008082526020820152610bba6121d1565b610c6660405180610200016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600060ff168152602001606081525090565b610c7287890189613862565b60ff166101c08401526001600160a01b039081166020840152166060820152610c99612203565b60a08301908152608083019182523060009081526001602052604081205460c085015291519051610ccb9190836125c8565b60e08401819052909150600003610ce157600080fd5b610d0282608001518360c00151610cf8919061363f565b8360e00151900490565b61010083015260a082015160c0830151610d1f91610cf89161363f565b61012083015260c0820151610d359030906128ae565b610d3e87612458565b96507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682606001516001600160a01b031603610ecc57610dc8877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101a083018190526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660408401526101008301516080840151610e3c929190610e20908290613628565b8561012001518660a00151610e359190613628565b600161290d565b610180840152610160830181905261012083018051610e5c90839061365e565b91508181525050610e9d7f00000000000000000000000000000000000000000000000000000000000000008360200151846101200151856101c001516129c8565b6101208201516101408301819052600061010084015260a083018051610ec4908390613628565b90525061105d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682606001516001600160a01b031614610f0e57600080fd5b610f59877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101a083018190526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660408401526101208301516101008401516080850151610fd1939291610fb591613628565b8561012001518660a00151610fca9190613628565b600061290d565b610180840152610160830181905261010083018051610ff190839061365e565b915081815250506110327f00000000000000000000000000000000000000000000000000000000000000008360200151846101000151856101c001516129c8565b61010082015161014083018190526000610120840152608083018051611059908390613628565b9052505b6001600160a01b03861615611111576001600160a01b0387168252604080516020601f87018190048102820181019092528581529086908690819084018382808284376000920191909152505050506101e0830152604051630eace54160e11b81526001600160a01b03871690631d59ca82906110de9085906004016139d5565b600060405180830381600087803b1580156110f857600080fd5b505af115801561110c573d6000803e3d6000fd5b505050505b61112382608001518360a001516127fe565b801561113f5761113b82608001518360a0015161236d565b600b555b604051806040016040528083606001516001600160a01b03168152602001836101400151815250925081602001516001600160a01b0316336001600160a01b03167fd175a80c109434bb89948928ab2475a6647c94244cb70002197896423c8833638461010001518561012001518660c001516040516111c1939291906137f8565b60405180910390a35050610a106001600855565b82804211156111f757604051630407b05b60e31b815260040160405180910390fd5b600061120588888888612ae0565b9050611248888286868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b9992505050565b61126557604051638baa579f60e01b815260040160405180910390fd5b611270888888612846565b5050505050505050565b600060065446146112925761128d612cc5565b905090565b5060075490565b60408051600280825260608083018452926020830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000816000815181106112ed576112ed6139e6565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110611341576113416139e6565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b60408051808201909152600080825260208201526113806121d1565b61141e604051806101c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600060ff168152602001606081525090565b61142a87890189613862565b60ff166101808401526001600160a01b039081166020840152166040820152600954600a5460a08301526080820152611461612203565b60e083015260c082015261147486612458565b95507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681604001516001600160a01b0316036115fc576114fe867f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101608201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166060820152608081015160c082015161154c9190613628565b8161010001818152505061157b81610160015162ffffff1682610100015183608001518460a00151600161290d565b610140830152610120820181905260e08201805161159a908390613628565b90525060208101516101008201516101208301516040516001600160a01b039093169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822926115ef926000918291613a14565b60405180910390a3611785565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681604001516001600160a01b03161461163e57600080fd5b611689867f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101608201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016606082015260a081015160e08201516116d79190613628565b8161010001818152505061170681610160015162ffffff1682610100015183608001518460a00151600061290d565b610140830152610120820181905260c082018051611725908390613628565b90525060208101516101008201516101208301516040516001600160a01b039093169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229261177c9260009291908390613a49565b60405180910390a35b60c08101516001600160801b0310156117b157604051631a93c68960e11b815260040160405180910390fd5b60e08101516001600160801b0310156117dd57604051631a93c68960e11b815260040160405180910390fd5b6117fb816060015182602001518361012001518461018001516129c8565b6001600160a01b038516156118af576001600160a01b0386168152604080516020601f86018190048102820181019092528481529085908590819084018382808284376000920191909152505050506101a082015260405163608dbcbb60e01b81526001600160a01b0386169063608dbcbb9061187c908490600401613b9b565b600060405180830381600087803b15801561189657600080fd5b505af11580156118aa573d6000803e3d6000fd5b505050505b6118c18160c001518260e001516127fe565b60608101516001600160a01b0316825261012001516020820152610a106001600855565b604051634625a94d60e01b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634625a94d9061193c9030908990899089908990600401613bac565b602060405180830381865afa158015611959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197d9190613c09565b95945050505050565b60058054610a2790613836565b600954600a54600091907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169087161483816119f9577f0000000000000000000000000000000000000000000000000000000000000000611a1b565b7f00000000000000000000000000000000000000000000000000000000000000005b9050611a39611a2b87838b612516565b62ffffff1688868686612d4e565b98975050505050505050565b6040516302a64b8360e21b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630a992e0c90611a94903090600401613127565b602060405180830381865afa158015611ab1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128d9190613c09565b33600090815260016020526040812080548391908390611af6908490613628565b90915550506001600160a01b0383166000818152600160205260409081902080548501905551339060008051602061412c83398151915290611b39908690613038565b60405180910390a350600192915050565b8380421115611b6c57604051630407b05b60e31b815260040160405180910390fd5b6000611b7a89898989612ae0565b9050600060018287878760405160008152602001604052604051611ba19493929190613c2a565b6020604051602081039080840390855afa158015611bc3573d6000803e3d6000fd5b505050602060405103519050896001600160a01b0316816001600160a01b031614611c0157604051638baa579f60e01b815260040160405180910390fd5b6001600160a01b038116611c2857604051638baa579f60e01b815260040160405180910390fd5b611c338a8a8a612846565b50505050505050505050565b6060611c496121d1565b611cb460405180610140016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600060ff168152602001606081525090565b611cc087890189613c52565b60ff166101008301526001600160a01b03166020820152611cdf612203565b606083019081526040808401928352306000908152600160205290812054608085015291519051611d119190836125c8565b60a08401819052909150600003611d2757600080fd5b611d4882604001518360800151611d3e919061363f565b8360a00151900490565b60c083015260608201516080830151611d6491611d3e9161363f565b60e08301526080820151611d799030906128ae565b611db27f000000000000000000000000000000000000000000000000000000000000000083602001518460c001518561010001516129c8565b611deb7f000000000000000000000000000000000000000000000000000000000000000083602001518460e001518561010001516129c8565b60c082015160408301805191909103905260e08201516060830180519190910390526001600160a01b03861615611ec957611e2587612458565b6001600160a01b03168252604080516020601f870181900481028201810190925285815290869086908190840183828082843760009201919091525050505061012083015260405163109ea27d60e31b81526001600160a01b038716906384f513e890611e96908590600401613d4e565b600060405180830381600087803b158015611eb057600080fd5b505af1158015611ec4573d6000803e3d6000fd5b505050505b611edb826040015183606001516127fe565b8015611ef757611ef38260400151836060015161236d565b600b555b6040805160028082526060820190925290816020015b6040805180820190915260008082526020820152815260200190600190039081611f0d57905050925060405180604001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018360c0015181525083600081518110611f8b57611f8b6139e6565b602002602001018190525060405180604001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018360e0015181525083600181518110611feb57611feb6139e6565b602002602001018190525081602001516001600160a01b0316336001600160a01b03167fd175a80c109434bb89948928ab2475a6647c94244cb70002197896423c8833638460c001518560e0015186608001516040516111c1939291906137f8565b600954600a54600091907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169087161483816120b3577f00000000000000000000000000000000000000000000000000000000000000006120d5565b7f00000000000000000000000000000000000000000000000000000000000000005b90506120f36120e5878a84612516565b62ffffff168886868661290d565b5098975050505050505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051600091606091839182916001600160a01b0387169161214891613d81565b600060405180830381855afa9150503d8060008114612183576040519150601f19603f3d011682016040523d82523d6000602084013e612188565b606091505b509150915081156121b4576001818060200190518101906121a99190613de5565b935093505050915091565b600060405180602001604052806000815250935093505050915091565b6002600854036121fc5760405162461bcd60e51b81526004016121f390613e20565b60405180910390fd5b6002600855565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f7888aec7f0000000000000000000000000000000000000000000000000000000000000000306040518363ffffffff1660e01b8152600401612274929190613e5b565b602060405180830381865afa158015612291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122b59190613e81565b604051633de222bb60e21b81529092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f7888aec90612326907f0000000000000000000000000000000000000000000000000000000000000000903090600401613e5b565b602060405180830381865afa158015612343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123679190613e81565b90509091565b60006001600160801b0383111561239757604051631a93c68960e11b815260040160405180910390fd5b6001600160801b038211156123bf57604051631a93c68960e11b815260040160405180910390fd5b610b976123cc838561363f565b70ffffffffffffffffffffffffffffffffff811160071b81811c68ffffffffffffffffff1060061b1781811c64ffffffffff1060051b1781811c62ffffff1060041b1781811c620100000160b5600192831c1b0260121c80830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b60006001600160a01b03821615612512576001600160a01b038216331461251257604051632af3bd5560e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063abcef554906124c5903390600401613127565b602060405180830381865afa1580156124e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125069190613eb5565b61251257506000919050565b5090565b6000612533848484604051806020016040528060008152506118e5565b949350505050565b60008083600003612551575060009050806125bd565b848610612589576125826125658688613628565b61256f908a61363f565b61257d620186a0600261363f565b900490565b90506125bd565b600083612596868961363f565b6125a0919061368c565b90506125b96125af828a613628565b61256f908b61363f565b9250505b965096945050505050565b600080600054905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634ccb20c06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126549190613ee1565b600b546001600160a01b038216151594509091508015612797578315612791578460000361268957612686878761236d565b94505b8085111561278c57600061269b611a45565b62ffffff1690506000816126af8489613628565b6126b9908761363f565b6126c3919061363f565b905060006126d1848461363f565b886126df85620186a0613628565b6126e9919061363f565b6126f3919061365e565b90506000612701828461368c565b905080156127875761271386826127a1565b604051631087d04360e31b81526001600160a01b0387169063843e82189061274690600190309086908a90600401613f17565b600060405180830381600087803b15801561276057600080fd5b505af1158015612774573d6000803e3d6000fd5b505050508087612784919061365e565b96505b505050505b612797565b6000600b555b5050935093915050565b806000808282546127b2919061365e565b90915550506001600160a01b0382166000818152600160205260408082208054850190555160008051602061412c833981519152906127f2908590613038565b60405180910390a35050565b600a81905560098290556040517fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a9061283a90849084906130b5565b60405180910390a15050565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906128a1908590613038565b60405180910390a3505050565b6001600160a01b038216600090815260016020526040812080548392906128d6908490613628565b90915550506000805482900381556040516001600160a01b0384169060008051602061412c833981519152906127f2908590613038565b6000808560000361292157600091506129be565b600061293088620186a0613628565b61293a908861363f565b9050612952612949898961363f565b620186a0900490565b9150831561298d5780612968620186a08861363f565b612972919061365e565b61297c868361363f565b612986919061368c565b92506129bc565b8061299b620186a08761363f565b6129a5919061365e565b6129af878361363f565b6129b9919061368c565b92505b505b9550959350505050565b8060ff16600003612a5a576040516317d5759960e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063beabacc890612a2390879087908790600401613f61565b600060405180830381600087803b158015612a3d57600080fd5b505af1158015612a51573d6000803e3d6000fd5b50505050612ada565b604051636cb568c160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636cb568c190612aac908790879087908790600401613f7c565b600060405180830381600087803b158015612ac657600080fd5b505af1158015611270573d6000803e3d6000fd5b50505050565b6000612aea61127a565b6001600160a01b038616600090815260036020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c992899289928992909190612b3883613fb1565b9190505587604051602001612b5296959493929190613fcb565b60405160208183030381529060405280519060200120604051602001612b7992919061401a565b604051602081830303815290604052805190602001209050949350505050565b600080612ba68484612e09565b9050846001600160a01b0316816001600160a01b031603612bda576001600160a01b03811615612bda576001915050610b97565b600080866001600160a01b0316631626ba7e60e01b8787604051602401612c0292919061404b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c409190613d81565b600060405180830381855afa9150503d8060008114612c7b576040519150601f19603f3d011682016040523d82523d6000602084013e612c80565b606091505b5091509150818015612c93575080516020145b8015612cba57508051630b135d3f60e11b90612cb89083016020908101908401613e81565b145b979650505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051612cf791906140dd565b604051908190038120612d3392917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc690469030906020016140e9565b60405160208183030381529060405280519060200120905090565b600084600003612d605750600061197d565b8115612dbb57612d7386620186a0613628565b612d7d8686613628565b612d87919061363f565b620186a0612d95878661363f565b612d9f919061363f565b612da9919061368c565b612db490600161365e565b905061197d565b612dc886620186a0613628565b612dd28685613628565b612ddc919061363f565b620186a0612dea878761363f565b612df4919061363f565b612dfe919061368c565b610a1090600161365e565b60008151604114612e1c5750600061055b565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612e62576000935050505061055b565b60018682858560405160008152602001604052604051612e859493929190613c2a565b6020604051602081039080840390855afa158015612ea7573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6001600160e01b031981165b8114612ed357600080fd5b50565b803561055b81612ebc565b600060208284031215612ef657612ef6600080fd5b60006125338484612ed6565b8015155b82525050565b6020810161055b8284612f02565b60008083601f840112612f2f57612f2f600080fd5b50813567ffffffffffffffff811115612f4a57612f4a600080fd5b602083019150836001820283011115612f6557612f65600080fd5b9250929050565b60006001600160a01b03821661055b565b612ec881612f6c565b803561055b81612f7d565b60008060008060008060808789031215612fad57612fad600080fd5b863567ffffffffffffffff811115612fc757612fc7600080fd5b612fd389828a01612f1a565b96509650506020612fe689828a01612f86565b9450506040612ff789828a01612f86565b935050606087013567ffffffffffffffff81111561301757613017600080fd5b61302389828a01612f1a565b92509250509295509295509295565b80612f06565b6020810161055b8284613032565b60005b83811015613061578181015183820152602001613049565b83811115612ada5750506000910152565b600061307c825190565b808452602084019350613093818560208601613046565b601f01601f19169290920192915050565b60208082528101610b978184613072565b604081016130c38285613032565b610b976020830184613032565b80612ec8565b803561055b816130d0565b600080604083850312156130f7576130f7600080fd5b60006131038585612f86565b9250506020613114858286016130d6565b9150509250929050565b612f0681612f6c565b6020810161055b828461311e565b60008060006060848603121561314d5761314d600080fd5b60006131598686612f86565b935050602061316a86828701612f86565b925050604061317b868287016130d6565b9150509250925092565b80516040830190613196848261311e565b506020820151612ada6020850182613032565b6040810161055b8284613185565b60008060008060008060a087890312156131d3576131d3600080fd5b60006131df8989612f86565b96505060206131f089828a01612f86565b955050604061320189828a016130d6565b945050606061321289828a016130d6565b935050608087013567ffffffffffffffff81111561301757613017600080fd5b60ff8116612f06565b6020810161055b8284613232565b6000613255838361311e565b505060200190565b6000613267825190565b80845260209384019383018060005b8381101561329b57815161328a8882613249565b975060208301925050600101613276565b509495945050505050565b60208082528101610b97818461325d565b6000602082840312156132cc576132cc600080fd5b60006125338484612f86565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613314576133146132d8565b6040525050565b600061332660405190565b905061333282826132ee565b919050565b600067ffffffffffffffff821115613351576133516132d8565b601f19601f83011660200192915050565b82818337506000910152565b600061338161337c84613337565b61331b565b90508281526020810184848401111561339c5761339c600080fd5b6133a7848285613362565b509392505050565b600082601f8301126133c3576133c3600080fd5b813561253384826020860161336e565b600080600080608085870312156133ec576133ec600080fd5b60006133f88787612f86565b945050602061340987828801612f86565b935050604061341a87828801612f86565b925050606085013567ffffffffffffffff81111561343a5761343a600080fd5b613446878288016133af565b91505092959194509250565b62ffffff8116612f06565b6020810161055b8284613452565b60008060006060848603121561348357613483600080fd5b600061348f8686612f86565b93505060206134a0868287016130d6565b925050604061317b86828701612f86565b61ffff8116612f06565b6020810161055b82846134b1565b60ff8116612ec8565b803561055b816134c9565b600080600080600080600060e0888a0312156134fb576134fb600080fd5b60006135078a8a612f86565b97505060206135188a828b01612f86565b96505060406135298a828b016130d6565b955050606061353a8a828b016130d6565b945050608061354b8a828b016134d2565b93505060a061355c8a828b016130d6565b92505060c061356d8a828b016130d6565b91505092959891949750929550565b6000806040838503121561359257613592600080fd5b600061359e8585612f86565b925050602061311485828601612f86565b60006135bb8383613185565b505060400190565b60006135cd825190565b80845260209384019383018060005b8381101561329b5781516135f088826135af565b9750602083019250506001016135dc565b60208082528101610b9781846135c3565b634e487b7160e01b600052601160045260246000fd5b60008282101561363a5761363a613612565b500390565b600081600019048311821515161561365957613659613612565b500290565b6000821982111561367157613671613612565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261369b5761369b613676565b500490565b80516000906102008401906136b5858261311e565b5060208301516136c8602086018261311e565b5060408301516136db6040860182613032565b5060608301516136ee6060860182613032565b5060808301516137016080860182613032565b5060a083015161371460a0860182613032565b5060c083015161372760c0860182613032565b5060e083015161373a60e0860182613032565b5061010083015161374f610100860182613032565b50610120830151613764610120860182613032565b50610140830151613779610140860182613032565b5061016083015161378e610160860182613032565b506101808301516137a3610180860182613032565b506101a08301516137b86101a0860182613032565b506101c08301516137cd6101c0860182613452565b506101e08301518482036101e086015261197d8282613072565b60208082528101610b9781846136a0565b606081016138068286613032565b6138136020830185613032565b6125336040830184613032565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061384a57607f821691505b60208210810361385c5761385c613820565b50919050565b60008060006060848603121561387a5761387a600080fd5b60006138868686612f86565b935050602061389786828701612f86565b925050604061317b868287016134d2565b80516000906102008401906138bd858261311e565b5060208301516138d0602086018261311e565b5060408301516138e3604086018261311e565b5060608301516138f6606086018261311e565b5060808301516139096080860182613032565b5060a083015161391c60a0860182613032565b5060c083015161392f60c0860182613032565b5060e083015161394260e0860182613032565b50610100830151613957610100860182613032565b5061012083015161396c610120860182613032565b50610140830151613981610140860182613032565b50610160830151613996610160860182613032565b506101808301516139ab610180860182613032565b506101a08301516139c06101a0860182613452565b506101c08301516137cd6101c0860182613232565b60208082528101610b9781846138a8565b634e487b7160e01b600052603260045260246000fd5b600061055b613a088381565b90565b612f06816139fc565b60808101613a228287613032565b613a2f6020830186613a0b565b613a3c6040830185613a0b565b61197d6060830184613032565b60808101613a578287613a0b565b613a646020830186613032565b613a716040830185613032565b61197d6060830184613a0b565b80516000906101c0840190613a93858261311e565b506020830151613aa6602086018261311e565b506040830151613ab9604086018261311e565b506060830151613acc606086018261311e565b506080830151613adf6080860182613032565b5060a0830151613af260a0860182613032565b5060c0830151613b0560c0860182613032565b5060e0830151613b1860e0860182613032565b50610100830151613b2d610100860182613032565b50610120830151613b42610120860182613032565b50610140830151613b57610140860182613032565b50610160830151613b6c610160860182613452565b50610180830151613b81610180860182613232565b506101a08301518482036101a086015261197d8282613072565b60208082528101610b978184613a7e565b60a08101613bba828861311e565b613bc7602083018761311e565b613bd4604083018661311e565b613be1606083018561311e565b8181036080830152612cba8184613072565b62ffffff8116612ec8565b805161055b81613bf3565b600060208284031215613c1e57613c1e600080fd5b60006125338484613bfe565b60808101613c388287613032565b613c456020830186613232565b613a3c6040830185613032565b60008060408385031215613c6857613c68600080fd5b6000613c748585612f86565b9250506020613114858286016134d2565b8051600090610140840190613c9a858261311e565b506020830151613cad602086018261311e565b506040830151613cc06040860182613032565b506060830151613cd36060860182613032565b506080830151613ce66080860182613032565b5060a0830151613cf960a0860182613032565b5060c0830151613d0c60c0860182613032565b5060e0830151613d1f60e0860182613032565b50610100830151613d34610100860182613232565b5061012083015184820361012086015261197d8282613072565b60208082528101610b978184613c85565b6000613d69825190565b613d77818560208601613046565b9290920192915050565b6000610b978284613d5f565b6000613d9b61337c84613337565b905082815260208101848484011115613db657613db6600080fd5b6133a7848285613046565b600082601f830112613dd557613dd5600080fd5b8151612533848260208601613d8d565b600060208284031215613dfa57613dfa600080fd5b815167ffffffffffffffff811115613e1457613e14600080fd5b61253384828501613dc1565b6020808252810161055b81601f81527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00602082015260400190565b60408101613e69828561311e565b610b97602083018461311e565b805161055b816130d0565b600060208284031215613e9657613e96600080fd5b60006125338484613e76565b801515612ec8565b805161055b81613ea2565b600060208284031215613eca57613eca600080fd5b60006125338484613eaa565b805161055b81612f7d565b600060208284031215613ef657613ef6600080fd5b60006125338484613ed6565b600061ffff821661055b565b612f0681613f02565b60a08101613f258287613f0e565b613f32602083018661311e565b613f3f6040830185613032565b613f4c6060830184613032565b81810360808301526000815260208101610a10565b60608101613f6f828661311e565b613813602083018561311e565b60808101613f8a828761311e565b613f97602083018661311e565b613fa46040830185613032565b61197d6060830184613232565b60006000198203613fc457613fc4613612565b5060010190565b60c08101613fd98289613032565b613fe6602083018861311e565b613ff3604083018761311e565b6140006060830186613032565b61400d6080830185613032565b612cba60a0830184613032565b61190160f01b815260020160006140318285613032565b6020820191506140418284613032565b5060200192915050565b604081016140598285613032565b81810360208301526125338184613072565b6000815461407881613836565b60018216801561408f57600181146140a4576140d4565b60ff19831686528115158202860193506140d4565b60008581526020902060005b838110156140cc578154888201526001909101906020016140b0565b838801955050505b50505092915050565b6000610b97828461406b565b60a081016140f78288613a0b565b6141046020830187613032565b6141116040830186613a0b565b61411e6060830185613032565b610a10608083018461311e56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212209d4df6080488c965e85c8d46a748d3e9c678e134194f5c0fad6ef2903c78217b64736f6c634300080f0033a26469706673582212204b619fda80c15b4e75b8d2761286fe37fd0165cae1297695220dd54ad6154e8764736f6c634300080f0033000000000000000000000000608cb7c3168427091f5994a45baf12083964b4a3

Deployed Bytecode

0x60806040523480156200001157600080fd5b50600436106200005e5760003560e01c806313b8683f14620000635780634625a94d1462000092578063531aa03e14620000b8578063d039f62214620000ec578063ee97f7f31462000105575b600080fd5b6200007a62000074366004620005fa565b6200012d565b6040516200008991906200066c565b60405180910390f35b620000a9620000a3366004620006a3565b62000264565b60405162000089919062000753565b6200007a620000c936600462000763565b60006020818152928152604080822090935290815220546001600160a01b031681565b620000f66200030e565b60405162000089919062000810565b6200007a7f000000000000000000000000608cb7c3168427091f5994a45baf12083964b4a381565b600080806200013f8486018662000763565b91509150806001600160a01b0316826001600160a01b03160362000176576040516333910aef60e11b815260040160405180910390fd5b816001600160a01b0316816001600160a01b031610156200019357905b6001600160a01b038216620001bb576040516333910aef60e11b815260040160405180910390fd5b620001c78282620003a8565b6001600160a01b0380841660008181526020818152604080832087861680855290835281842080549688166001600160a01b03199788168117909155848452828520868652909352928190208054909516909117909355915192955090917f9c5d829b9b23efc461f9aeef91979ec04bb903feb3bee4f26d22114abfc7335b90620002549087906200066c565b60405180910390a3505092915050565b604051634625a94d60e01b81526000906001600160a01b037f000000000000000000000000608cb7c3168427091f5994a45baf12083964b4a31690634625a94d90620002bf908a908a908a908a908a908a906004016200085c565b602060405180830381865afa158015620002dd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003039190620008d3565b979650505050505050565b6060600180546200031f9062000916565b80601f01602080910402602001604051908101604052809291908181526020018280546200034d9062000916565b80156200039e5780601f1062000372576101008083540402835291602001916200039e565b820191906000526020600020905b8154815290600101906020018083116200038057829003601f168201915b5050505050905090565b6040516370a0823160e01b81526000906001600160a01b038416906370a0823190620003d99030906004016200066c565b602060405180830381865afa158015620003f7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200041d91906200095a565b506040516370a0823160e01b81526001600160a01b038316906370a08231906200044c9030906004016200066c565b602060405180830381865afa1580156200046a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200049091906200095a565b5060008383604051602001620004a89291906200097f565b60408051601f1981840301815291905290506001620004c8828262000a6b565b50805160208201206040518190620004e09062000594565b8190604051809103906000f590508015801562000501573d6000803e3d6000fd5b5060405163784198d960e01b81529093506001600160a01b037f000000000000000000000000608cb7c3168427091f5994a45baf12083964b4a3169063784198d99062000558908690600190879060040162000b54565b600060405180830381600087803b1580156200057357600080fd5b505af115801562000588573d6000803e3d6000fd5b50505050505092915050565b614d0d8062000b9183390190565b60008083601f840112620005b957620005b9600080fd5b50813567ffffffffffffffff811115620005d657620005d6600080fd5b602083019150836001820283011115620005f357620005f3600080fd5b9250929050565b60008060208385031215620006125762000612600080fd5b823567ffffffffffffffff8111156200062e576200062e600080fd5b6200063c85828601620005a2565b92509250509250929050565b60006001600160a01b0382165b92915050565b620006668162000648565b82525050565b602081016200065582846200065b565b620006878162000648565b81146200069357600080fd5b50565b803562000655816200067c565b60008060008060008060a08789031215620006c157620006c1600080fd5b6000620006cf898962000696565b9650506020620006e289828a0162000696565b9550506040620006f589828a0162000696565b94505060606200070889828a0162000696565b935050608087013567ffffffffffffffff8111156200072a576200072a600080fd5b6200073889828a01620005a2565b92509250509295509295509295565b62ffffff811662000666565b6020810162000655828462000747565b600080604083850312156200077b576200077b600080fd5b600062000789858562000696565b92505060206200079c8582860162000696565b9150509250929050565b60005b83811015620007c3578181015183820152602001620007a9565b83811115620007d3576000848401525b50505050565b6000620007e4825190565b808452602084019350620007fd818560208601620007a6565b601f19601f8201165b9093019392505050565b60208082528101620008238184620007d9565b9392505050565b82818337506000910152565b81835260006020840193506200084e8385846200082a565b601f19601f84011662000806565b60a081016200086c82896200065b565b6200087b60208301886200065b565b6200088a60408301876200065b565b6200089960608301866200065b565b8181036080830152620008ae81848662000836565b98975050505050505050565b62ffffff811662000687565b80516200065581620008ba565b600060208284031215620008ea57620008ea600080fd5b6000620008f88484620008c6565b949350505050565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200092b57607f821691505b60208210810362000940576200094062000900565b50919050565b8062000687565b8051620006558162000946565b600060208284031215620009715762000971600080fd5b6000620008f884846200094d565b604081016200098f82856200065b565b6200082360208301846200065b565b634e487b7160e01b600052604160045260246000fd5b600062000655620009c28381565b90565b620009d083620009b4565b81546008840282811b60001990911b908116901990911617825550505050565b6000620009ff818484620009c5565b505050565b8181101562000a235762000a1a600082620009f0565b60010162000a04565b5050565b601f821115620009ff576000818152602090206020601f8501048101602085101562000a505750805b62000a646020601f86010483018262000a04565b5050505050565b815167ffffffffffffffff81111562000a885762000a886200099e565b62000a94825462000916565b62000aa182828562000a27565b6020601f83116001811462000ad8576000841562000abf5750858201515b600019600886021c198116600286021786555062000b34565b600085815260208120601f198616915b8281101562000b0a578885015182556020948501946001909201910162000ae8565b8683101562000b275784890151600019601f89166008021c191682555b6001600288020188555050505b505050505050565b600061ffff821662000655565b620006668162000b3c565b6060810162000b6482866200065b565b62000b73602083018562000b49565b818103604083015262000b878184620007d9565b9594505050505056fe61012060405260126080523480156200001757600080fd5b5060016008819055506000336001600160a01b031663d039f6226040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000061573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200008b919081019062000597565b905060008082806020019051810190620000a6919062000611565b915091506000336001600160a01b031663ee97f7f36040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000111919062000654565b9050806001600160a01b031660a0816001600160a01b031681525050806001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200016c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000192919062000654565b6001600160a01b0390811660c05282811661010052831660e052600080620001c685620002c2602090811b6200210017901c565b91509150600080620001e386620002c260201b620021001760201c565b91509150838015620001f25750815b1562000251576200024b8382604051602001620002119291906200069e565b604051602081830303815290604052848360405160200162000235929190620006f3565b60408051601f198184030181529190526200039a565b620002b4565b620002b46040518060400160405280601381526020017f53796e635377617020436c6173736963204c500000000000000000000000000081525060405180604001604052806004815260200163063534c560e41b8152506200039a60201b60201c565b505050505050505062000a13565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051600091606091839182916001600160a01b038716916200030c9162000730565b600060405180830381855afa9150503d806000811462000349576040519150601f19603f3d011682016040523d82523d6000602084013e6200034e565b606091505b509150915081156200037d5760018180602001905181019062000372919062000597565b935093505050915091565b600060405180602001604052806000815250935093505050915091565b6004620003a8838262000842565b506005620003b7828262000842565b5046600655620003c6620003cd565b6007555050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60046040516200040191906200098c565b6040519081900381206200043f92917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69046903090602001620009bd565b60405160208183030381529060405280519060200120905090565b634e487b7160e01b600052604160045260246000fd5b601f19601f83011681018181106001600160401b03821117156200049857620004986200045a565b6040525050565b6000620004ab60405190565b9050620004b9828262000470565b919050565b60006001600160401b03821115620004da57620004da6200045a565b601f19601f83011660200192915050565b60005b8381101562000508578181015183820152602001620004ee565b8381111562000518576000848401525b50505050565b6000620005356200052f84620004be565b6200049f565b905082815260208101848484011115620005525762000552600080fd5b6200055f848285620004eb565b509392505050565b600082601f8301126200057d576200057d600080fd5b81516200058f8482602086016200051e565b949350505050565b600060208284031215620005ae57620005ae600080fd5b81516001600160401b03811115620005c957620005c9600080fd5b6200058f8482850162000567565b60006001600160a01b0382165b92915050565b620005f581620005d7565b81146200060157600080fd5b50565b8051620005e481620005ea565b60008060408385031215620006295762000629600080fd5b600062000637858562000604565b92505060206200064a8582860162000604565b9150509250929050565b6000602082840312156200066b576200066b600080fd5b60006200058f848462000604565b600062000684825190565b62000694818560208601620004eb565b9290920192915050565b68029bcb731a9bbb0b8160bd1b81526009016000620006be828562000679565b602f60f81b81526001019150620006d6828462000679565b6a020436c6173736963204c560ac1b81529150600b82016200058f565b600062000701828562000679565b602f60f81b8152600101915062000719828462000679565b6402063534c560dc1b81529150600582016200058f565b60006200073e828462000679565b9392505050565b634e487b7160e01b600052602260045260246000fd5b6002810460018216806200077057607f821691505b60208210810362000785576200078562000745565b50919050565b6000620005e4620007998381565b90565b620007a7836200078b565b81546008840282811b60001990911b908116901990911617825550505050565b6000620007d68184846200079c565b505050565b81811015620007fa57620007f1600082620007c7565b600101620007db565b5050565b601f821115620007d6576000818152602090206020601f85010481016020851015620008275750805b6200083b6020601f860104830182620007db565b5050505050565b81516001600160401b038111156200085e576200085e6200045a565b6200086a82546200075b565b62000877828285620007fe565b6020601f831160018114620008ae5760008415620008955750858201515b600019600886021c19811660028602178655506200090a565b600085815260208120601f198616915b82811015620008e05788850151825560209485019460019092019101620008be565b86831015620008fd5784890151600019601f89166008021c191682555b6001600288020188555050505b505050505050565b6000815462000921816200075b565b6001821680156200093b5760018114620009515762000983565b60ff198316865281151582028601935062000983565b60008581526020902060005b838110156200097b578154888201526001909101906020016200095d565b838801955050505b50505092915050565b60006200073e828462000912565b620009a5816200078b565b82525050565b80620009a5565b620009a581620005d7565b60a08101620009cd82886200099a565b620009dc6020830187620009ab565b620009eb60408301866200099a565b620009fa6060830185620009ab565b62000a096080830184620009b2565b9695505050505050565b60805160a05160c05160e0516101005161418162000b8c6000396000818161042e015281816106fd0152818161073701528181610d4201528181610da401528181610e6801528181610f1401528181610f700152818161130f015281816114da01528181611513015281816115fe01528181611644015281816119fb01528181611db701528181611fa3015281816120b501526122fc015260008181610288015281816106dc0152818161075801528181610d8301528181610ddf01528181610ece01528181610f3501528181610ffd015281816112bb01528181611478015281816114b9015281816116650152818161169e0152818161199f015281816119d501528181611d7e01528181611f43015281816120590152818161208f01526122370152600081816104da01528181612208015281816122cf015281816129ea0152612a71015260008181610493015281816118ff01528181611a5f0152818161249001526125d40152600061030d01526141816000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c806370a082311161010f578063b1dd61b6116100a2578063ee97f7f311610071578063ee97f7f31461048e578063f66eab5b146104b5578063fbfa77cf146104d5578063ff9c8ac6146104fc57600080fd5b8063b1dd61b614610414578063d21220a714610429578063d505accf14610450578063dd62ed3e1461046357600080fd5b806395d89b41116100de57806395d89b41146103de578063a287c795146103e6578063a5a41031146103f9578063a9059cbb1461040157600080fd5b806370a082311461036b5780637132bb7f1461038b5780637ecebe001461039e5780638b4c5470146103be57600080fd5b806323b872dd116101875780633644e515116101565780633644e5151461033c578063443cb4bc146103445780635a76f25e1461034d57806367e4ac2c1461035657600080fd5b806323b872dd146102c057806327b0bcea146102d35780632c0198cc146102f3578063313ce5671461030857600080fd5b80630902f1ac116101c35780630902f1ac1461025c578063095ea7b3146102705780630dfe16811461028357806318160ddd146102b757600080fd5b806301ffc9a7146101f557806303e7286a1461021e57806306fdde031461023e57806307f293f714610253575b600080fd5b610208610203366004612ee1565b61050f565b6040516102159190612f0c565b60405180910390f35b61023161022c366004612f91565b610561565b6040516102159190613038565b610246610a1a565b60405161021591906130a4565b610231600b5481565b600954600a546040516102159291906130b5565b61020861027e3660046130e1565b610aa8565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b6040516102159190613127565b61023160005481565b6102086102ce366004613135565b610abe565b6102e66102e1366004612f91565b610b9e565b60405161021591906131a9565b6103066103013660046131b7565b6111d5565b005b61032f7f000000000000000000000000000000000000000000000000000000000000000081565b604051610215919061323b565b61023161127a565b61023160095481565b610231600a5481565b61035e611299565b60405161021591906132a6565b6102316103793660046132b7565b60016020526000908152604090205481565b6102e6610399366004612f91565b611364565b6102316103ac3660046132b7565b60036020526000908152604090205481565b6103d16103cc3660046133d3565b6118e5565b604051610215919061345d565b610246611986565b6102316103f436600461346b565b611993565b6103d1611a45565b61020861040f3660046130e1565b611ad5565b61041c600181565b60405161021591906134bb565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b61030661045e3660046134dd565b611b4a565b61023161047136600461357c565b600260209081526000928352604080842090915290825290205481565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b6104c86104c3366004612f91565b611c3f565b6040516102159190613601565b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b61023161050a36600461346b565b61204d565b60006001600160e01b031982166301ffc9a760e01b148061054057506001600160e01b0319821663d505accf60e01b145b8061055b57506001600160e01b03198216630b00663360e21b145b92915050565b600061056b6121d1565b61060260405180610200016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001606081525090565b61060e878901896132b7565b6001600160a01b03166020820152600954600a5460608301526040820152610634612203565b60a083018190526080830182905261064c919061236d565b610140820152604081015160808201516106669190613628565b60c0820152606081015160a082015161067f9190613628565b60e082015261068d86612458565b9550600081604001516000146106c3576106be82606001518360c001516106b4919061363f565b8360400151900490565b6106c6565b60005b60e08301519091508111801561073157610721887f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101c0840152610788565b61077c887f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101c08401525b6107b0836101c0015162ffffff168460c001518560e00151858760400151886060015161253b565b61012085015261010084018190526040840180516107cf90839061365e565b9052506101208301516060840180516107e990839061365e565b90525060408301516060840151610800919061236d565b610160840181905260009061081890829081906125c8565b6101808601819052909150600003610855576103e884610140015161083d9190613628565b6101a085015261085060006103e86127a1565b61088d565b610160840151610180850151610140860151610872908390613628565b61087c919061363f565b610886919061368c565b6101a08501525b836101a001516000036108b357604051633489be7560e21b815260040160405180910390fd5b6108c68460200151856101a001516127a1565b6001600160a01b0388161561097a576001600160a01b0389168452604080516020601f89018190048102820181019092528781529088908890819084018382808284376000920191909152505050506101e0850152604051630204997360e41b81526001600160a01b038916906320499730906109479087906004016137e7565b600060405180830381600087803b15801561096157600080fd5b505af1158015610975573d6000803e3d6000fd5b505050505b61098c84608001518560a001516127fe565b801561099c57610140840151600b555b83602001516001600160a01b0316336001600160a01b03167fa8137fff86647d8a402117b9c5dbda627f721d3773338fb9678c83e54ed390808660c001518760e00151886101a001516040516109f4939291906137f8565b60405180910390a35050506101a001519050610a106001600855565b9695505050505050565b60048054610a2790613836565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5390613836565b8015610aa05780601f10610a7557610100808354040283529160200191610aa0565b820191906000526020600020905b815481529060010190602001808311610a8357829003601f168201915b505050505081565b6000610ab5338484612846565b50600192915050565b6001600160a01b03831660009081526002602090815260408083203384529091528120546000198114610b1a57610af58382613628565b6001600160a01b03861660009081526002602090815260408083203384529091529020555b6001600160a01b03851660009081526001602052604081208054859290610b42908490613628565b90915550506001600160a01b038085166000818152600160205260409081902080548701905551909187169060008051602061412c83398151915290610b89908790613038565b60405180910390a360019150505b9392505050565b6040805180820190915260008082526020820152610bba6121d1565b610c6660405180610200016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600060ff168152602001606081525090565b610c7287890189613862565b60ff166101c08401526001600160a01b039081166020840152166060820152610c99612203565b60a08301908152608083019182523060009081526001602052604081205460c085015291519051610ccb9190836125c8565b60e08401819052909150600003610ce157600080fd5b610d0282608001518360c00151610cf8919061363f565b8360e00151900490565b61010083015260a082015160c0830151610d1f91610cf89161363f565b61012083015260c0820151610d359030906128ae565b610d3e87612458565b96507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682606001516001600160a01b031603610ecc57610dc8877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101a083018190526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660408401526101008301516080840151610e3c929190610e20908290613628565b8561012001518660a00151610e359190613628565b600161290d565b610180840152610160830181905261012083018051610e5c90839061365e565b91508181525050610e9d7f00000000000000000000000000000000000000000000000000000000000000008360200151846101200151856101c001516129c8565b6101208201516101408301819052600061010084015260a083018051610ec4908390613628565b90525061105d565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031682606001516001600160a01b031614610f0e57600080fd5b610f59877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101a083018190526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660408401526101208301516101008401516080850151610fd1939291610fb591613628565b8561012001518660a00151610fca9190613628565b600061290d565b610180840152610160830181905261010083018051610ff190839061365e565b915081815250506110327f00000000000000000000000000000000000000000000000000000000000000008360200151846101000151856101c001516129c8565b61010082015161014083018190526000610120840152608083018051611059908390613628565b9052505b6001600160a01b03861615611111576001600160a01b0387168252604080516020601f87018190048102820181019092528581529086908690819084018382808284376000920191909152505050506101e0830152604051630eace54160e11b81526001600160a01b03871690631d59ca82906110de9085906004016139d5565b600060405180830381600087803b1580156110f857600080fd5b505af115801561110c573d6000803e3d6000fd5b505050505b61112382608001518360a001516127fe565b801561113f5761113b82608001518360a0015161236d565b600b555b604051806040016040528083606001516001600160a01b03168152602001836101400151815250925081602001516001600160a01b0316336001600160a01b03167fd175a80c109434bb89948928ab2475a6647c94244cb70002197896423c8833638461010001518561012001518660c001516040516111c1939291906137f8565b60405180910390a35050610a106001600855565b82804211156111f757604051630407b05b60e31b815260040160405180910390fd5b600061120588888888612ae0565b9050611248888286868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612b9992505050565b61126557604051638baa579f60e01b815260040160405180910390fd5b611270888888612846565b5050505050505050565b600060065446146112925761128d612cc5565b905090565b5060075490565b60408051600280825260608083018452926020830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000816000815181106112ed576112ed6139e6565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110611341576113416139e6565b60200260200101906001600160a01b031690816001600160a01b03168152505090565b60408051808201909152600080825260208201526113806121d1565b61141e604051806101c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600062ffffff168152602001600060ff168152602001606081525090565b61142a87890189613862565b60ff166101808401526001600160a01b039081166020840152166040820152600954600a5460a08301526080820152611461612203565b60e083015260c082015261147486612458565b95507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681604001516001600160a01b0316036115fc576114fe867f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101608201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166060820152608081015160c082015161154c9190613628565b8161010001818152505061157b81610160015162ffffff1682610100015183608001518460a00151600161290d565b610140830152610120820181905260e08201805161159a908390613628565b90525060208101516101008201516101208301516040516001600160a01b039093169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822926115ef926000918291613a14565b60405180910390a3611785565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681604001516001600160a01b03161461163e57600080fd5b611689867f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000612516565b62ffffff166101608201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016606082015260a081015160e08201516116d79190613628565b8161010001818152505061170681610160015162ffffff1682610100015183608001518460a00151600061290d565b610140830152610120820181905260c082018051611725908390613628565b90525060208101516101008201516101208301516040516001600160a01b039093169233927fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d8229261177c9260009291908390613a49565b60405180910390a35b60c08101516001600160801b0310156117b157604051631a93c68960e11b815260040160405180910390fd5b60e08101516001600160801b0310156117dd57604051631a93c68960e11b815260040160405180910390fd5b6117fb816060015182602001518361012001518461018001516129c8565b6001600160a01b038516156118af576001600160a01b0386168152604080516020601f86018190048102820181019092528481529085908590819084018382808284376000920191909152505050506101a082015260405163608dbcbb60e01b81526001600160a01b0386169063608dbcbb9061187c908490600401613b9b565b600060405180830381600087803b15801561189657600080fd5b505af11580156118aa573d6000803e3d6000fd5b505050505b6118c18160c001518260e001516127fe565b60608101516001600160a01b0316825261012001516020820152610a106001600855565b604051634625a94d60e01b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690634625a94d9061193c9030908990899089908990600401613bac565b602060405180830381865afa158015611959573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197d9190613c09565b95945050505050565b60058054610a2790613836565b600954600a54600091907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169087161483816119f9577f0000000000000000000000000000000000000000000000000000000000000000611a1b565b7f00000000000000000000000000000000000000000000000000000000000000005b9050611a39611a2b87838b612516565b62ffffff1688868686612d4e565b98975050505050505050565b6040516302a64b8360e21b81526000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630a992e0c90611a94903090600401613127565b602060405180830381865afa158015611ab1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128d9190613c09565b33600090815260016020526040812080548391908390611af6908490613628565b90915550506001600160a01b0383166000818152600160205260409081902080548501905551339060008051602061412c83398151915290611b39908690613038565b60405180910390a350600192915050565b8380421115611b6c57604051630407b05b60e31b815260040160405180910390fd5b6000611b7a89898989612ae0565b9050600060018287878760405160008152602001604052604051611ba19493929190613c2a565b6020604051602081039080840390855afa158015611bc3573d6000803e3d6000fd5b505050602060405103519050896001600160a01b0316816001600160a01b031614611c0157604051638baa579f60e01b815260040160405180910390fd5b6001600160a01b038116611c2857604051638baa579f60e01b815260040160405180910390fd5b611c338a8a8a612846565b50505050505050505050565b6060611c496121d1565b611cb460405180610140016040528060006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600060ff168152602001606081525090565b611cc087890189613c52565b60ff166101008301526001600160a01b03166020820152611cdf612203565b606083019081526040808401928352306000908152600160205290812054608085015291519051611d119190836125c8565b60a08401819052909150600003611d2757600080fd5b611d4882604001518360800151611d3e919061363f565b8360a00151900490565b60c083015260608201516080830151611d6491611d3e9161363f565b60e08301526080820151611d799030906128ae565b611db27f000000000000000000000000000000000000000000000000000000000000000083602001518460c001518561010001516129c8565b611deb7f000000000000000000000000000000000000000000000000000000000000000083602001518460e001518561010001516129c8565b60c082015160408301805191909103905260e08201516060830180519190910390526001600160a01b03861615611ec957611e2587612458565b6001600160a01b03168252604080516020601f870181900481028201810190925285815290869086908190840183828082843760009201919091525050505061012083015260405163109ea27d60e31b81526001600160a01b038716906384f513e890611e96908590600401613d4e565b600060405180830381600087803b158015611eb057600080fd5b505af1158015611ec4573d6000803e3d6000fd5b505050505b611edb826040015183606001516127fe565b8015611ef757611ef38260400151836060015161236d565b600b555b6040805160028082526060820190925290816020015b6040805180820190915260008082526020820152815260200190600190039081611f0d57905050925060405180604001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018360c0015181525083600081518110611f8b57611f8b6139e6565b602002602001018190525060405180604001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020018360e0015181525083600181518110611feb57611feb6139e6565b602002602001018190525081602001516001600160a01b0316336001600160a01b03167fd175a80c109434bb89948928ab2475a6647c94244cb70002197896423c8833638460c001518560e0015186608001516040516111c1939291906137f8565b600954600a54600091907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081169087161483816120b3577f00000000000000000000000000000000000000000000000000000000000000006120d5565b7f00000000000000000000000000000000000000000000000000000000000000005b90506120f36120e5878a84612516565b62ffffff168886868661290d565b5098975050505050505050565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b1790529051600091606091839182916001600160a01b0387169161214891613d81565b600060405180830381855afa9150503d8060008114612183576040519150601f19603f3d011682016040523d82523d6000602084013e612188565b606091505b509150915081156121b4576001818060200190518101906121a99190613de5565b935093505050915091565b600060405180602001604052806000815250935093505050915091565b6002600854036121fc5760405162461bcd60e51b81526004016121f390613e20565b60405180910390fd5b6002600855565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f7888aec7f0000000000000000000000000000000000000000000000000000000000000000306040518363ffffffff1660e01b8152600401612274929190613e5b565b602060405180830381865afa158015612291573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122b59190613e81565b604051633de222bb60e21b81529092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f7888aec90612326907f0000000000000000000000000000000000000000000000000000000000000000903090600401613e5b565b602060405180830381865afa158015612343573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123679190613e81565b90509091565b60006001600160801b0383111561239757604051631a93c68960e11b815260040160405180910390fd5b6001600160801b038211156123bf57604051631a93c68960e11b815260040160405180910390fd5b610b976123cc838561363f565b70ffffffffffffffffffffffffffffffffff811160071b81811c68ffffffffffffffffff1060061b1781811c64ffffffffff1060051b1781811c62ffffff1060041b1781811c620100000160b5600192831c1b0260121c80830401811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c908190048111900390565b60006001600160a01b03821615612512576001600160a01b038216331461251257604051632af3bd5560e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063abcef554906124c5903390600401613127565b602060405180830381865afa1580156124e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125069190613eb5565b61251257506000919050565b5090565b6000612533848484604051806020016040528060008152506118e5565b949350505050565b60008083600003612551575060009050806125bd565b848610612589576125826125658688613628565b61256f908a61363f565b61257d620186a0600261363f565b900490565b90506125bd565b600083612596868961363f565b6125a0919061368c565b90506125b96125af828a613628565b61256f908b61363f565b9250505b965096945050505050565b600080600054905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316634ccb20c06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612630573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126549190613ee1565b600b546001600160a01b038216151594509091508015612797578315612791578460000361268957612686878761236d565b94505b8085111561278c57600061269b611a45565b62ffffff1690506000816126af8489613628565b6126b9908761363f565b6126c3919061363f565b905060006126d1848461363f565b886126df85620186a0613628565b6126e9919061363f565b6126f3919061365e565b90506000612701828461368c565b905080156127875761271386826127a1565b604051631087d04360e31b81526001600160a01b0387169063843e82189061274690600190309086908a90600401613f17565b600060405180830381600087803b15801561276057600080fd5b505af1158015612774573d6000803e3d6000fd5b505050508087612784919061365e565b96505b505050505b612797565b6000600b555b5050935093915050565b806000808282546127b2919061365e565b90915550506001600160a01b0382166000818152600160205260408082208054850190555160008051602061412c833981519152906127f2908590613038565b60405180910390a35050565b600a81905560098290556040517fcf2aa50876cdfbb541206f89af0ee78d44a2abf8d328e37fa4917f982149848a9061283a90849084906130b5565b60405180910390a15050565b6001600160a01b0380841660008181526002602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906128a1908590613038565b60405180910390a3505050565b6001600160a01b038216600090815260016020526040812080548392906128d6908490613628565b90915550506000805482900381556040516001600160a01b0384169060008051602061412c833981519152906127f2908590613038565b6000808560000361292157600091506129be565b600061293088620186a0613628565b61293a908861363f565b9050612952612949898961363f565b620186a0900490565b9150831561298d5780612968620186a08861363f565b612972919061365e565b61297c868361363f565b612986919061368c565b92506129bc565b8061299b620186a08761363f565b6129a5919061365e565b6129af878361363f565b6129b9919061368c565b92505b505b9550959350505050565b8060ff16600003612a5a576040516317d5759960e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063beabacc890612a2390879087908790600401613f61565b600060405180830381600087803b158015612a3d57600080fd5b505af1158015612a51573d6000803e3d6000fd5b50505050612ada565b604051636cb568c160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636cb568c190612aac908790879087908790600401613f7c565b600060405180830381600087803b158015612ac657600080fd5b505af1158015611270573d6000803e3d6000fd5b50505050565b6000612aea61127a565b6001600160a01b038616600090815260036020526040812080547f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c992899289928992909190612b3883613fb1565b9190505587604051602001612b5296959493929190613fcb565b60405160208183030381529060405280519060200120604051602001612b7992919061401a565b604051602081830303815290604052805190602001209050949350505050565b600080612ba68484612e09565b9050846001600160a01b0316816001600160a01b031603612bda576001600160a01b03811615612bda576001915050610b97565b600080866001600160a01b0316631626ba7e60e01b8787604051602401612c0292919061404b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612c409190613d81565b600060405180830381855afa9150503d8060008114612c7b576040519150601f19603f3d011682016040523d82523d6000602084013e612c80565b606091505b5091509150818015612c93575080516020145b8015612cba57508051630b135d3f60e11b90612cb89083016020908101908401613e81565b145b979650505050505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051612cf791906140dd565b604051908190038120612d3392917fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc690469030906020016140e9565b60405160208183030381529060405280519060200120905090565b600084600003612d605750600061197d565b8115612dbb57612d7386620186a0613628565b612d7d8686613628565b612d87919061363f565b620186a0612d95878661363f565b612d9f919061363f565b612da9919061368c565b612db490600161365e565b905061197d565b612dc886620186a0613628565b612dd28685613628565b612ddc919061363f565b620186a0612dea878761363f565b612df4919061363f565b612dfe919061368c565b610a1090600161365e565b60008151604114612e1c5750600061055b565b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612e62576000935050505061055b565b60018682858560405160008152602001604052604051612e859493929190613c2a565b6020604051602081039080840390855afa158015612ea7573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b6001600160e01b031981165b8114612ed357600080fd5b50565b803561055b81612ebc565b600060208284031215612ef657612ef6600080fd5b60006125338484612ed6565b8015155b82525050565b6020810161055b8284612f02565b60008083601f840112612f2f57612f2f600080fd5b50813567ffffffffffffffff811115612f4a57612f4a600080fd5b602083019150836001820283011115612f6557612f65600080fd5b9250929050565b60006001600160a01b03821661055b565b612ec881612f6c565b803561055b81612f7d565b60008060008060008060808789031215612fad57612fad600080fd5b863567ffffffffffffffff811115612fc757612fc7600080fd5b612fd389828a01612f1a565b96509650506020612fe689828a01612f86565b9450506040612ff789828a01612f86565b935050606087013567ffffffffffffffff81111561301757613017600080fd5b61302389828a01612f1a565b92509250509295509295509295565b80612f06565b6020810161055b8284613032565b60005b83811015613061578181015183820152602001613049565b83811115612ada5750506000910152565b600061307c825190565b808452602084019350613093818560208601613046565b601f01601f19169290920192915050565b60208082528101610b978184613072565b604081016130c38285613032565b610b976020830184613032565b80612ec8565b803561055b816130d0565b600080604083850312156130f7576130f7600080fd5b60006131038585612f86565b9250506020613114858286016130d6565b9150509250929050565b612f0681612f6c565b6020810161055b828461311e565b60008060006060848603121561314d5761314d600080fd5b60006131598686612f86565b935050602061316a86828701612f86565b925050604061317b868287016130d6565b9150509250925092565b80516040830190613196848261311e565b506020820151612ada6020850182613032565b6040810161055b8284613185565b60008060008060008060a087890312156131d3576131d3600080fd5b60006131df8989612f86565b96505060206131f089828a01612f86565b955050604061320189828a016130d6565b945050606061321289828a016130d6565b935050608087013567ffffffffffffffff81111561301757613017600080fd5b60ff8116612f06565b6020810161055b8284613232565b6000613255838361311e565b505060200190565b6000613267825190565b80845260209384019383018060005b8381101561329b57815161328a8882613249565b975060208301925050600101613276565b509495945050505050565b60208082528101610b97818461325d565b6000602082840312156132cc576132cc600080fd5b60006125338484612f86565b634e487b7160e01b600052604160045260246000fd5b601f19601f830116810181811067ffffffffffffffff82111715613314576133146132d8565b6040525050565b600061332660405190565b905061333282826132ee565b919050565b600067ffffffffffffffff821115613351576133516132d8565b601f19601f83011660200192915050565b82818337506000910152565b600061338161337c84613337565b61331b565b90508281526020810184848401111561339c5761339c600080fd5b6133a7848285613362565b509392505050565b600082601f8301126133c3576133c3600080fd5b813561253384826020860161336e565b600080600080608085870312156133ec576133ec600080fd5b60006133f88787612f86565b945050602061340987828801612f86565b935050604061341a87828801612f86565b925050606085013567ffffffffffffffff81111561343a5761343a600080fd5b613446878288016133af565b91505092959194509250565b62ffffff8116612f06565b6020810161055b8284613452565b60008060006060848603121561348357613483600080fd5b600061348f8686612f86565b93505060206134a0868287016130d6565b925050604061317b86828701612f86565b61ffff8116612f06565b6020810161055b82846134b1565b60ff8116612ec8565b803561055b816134c9565b600080600080600080600060e0888a0312156134fb576134fb600080fd5b60006135078a8a612f86565b97505060206135188a828b01612f86565b96505060406135298a828b016130d6565b955050606061353a8a828b016130d6565b945050608061354b8a828b016134d2565b93505060a061355c8a828b016130d6565b92505060c061356d8a828b016130d6565b91505092959891949750929550565b6000806040838503121561359257613592600080fd5b600061359e8585612f86565b925050602061311485828601612f86565b60006135bb8383613185565b505060400190565b60006135cd825190565b80845260209384019383018060005b8381101561329b5781516135f088826135af565b9750602083019250506001016135dc565b60208082528101610b9781846135c3565b634e487b7160e01b600052601160045260246000fd5b60008282101561363a5761363a613612565b500390565b600081600019048311821515161561365957613659613612565b500290565b6000821982111561367157613671613612565b500190565b634e487b7160e01b600052601260045260246000fd5b60008261369b5761369b613676565b500490565b80516000906102008401906136b5858261311e565b5060208301516136c8602086018261311e565b5060408301516136db6040860182613032565b5060608301516136ee6060860182613032565b5060808301516137016080860182613032565b5060a083015161371460a0860182613032565b5060c083015161372760c0860182613032565b5060e083015161373a60e0860182613032565b5061010083015161374f610100860182613032565b50610120830151613764610120860182613032565b50610140830151613779610140860182613032565b5061016083015161378e610160860182613032565b506101808301516137a3610180860182613032565b506101a08301516137b86101a0860182613032565b506101c08301516137cd6101c0860182613452565b506101e08301518482036101e086015261197d8282613072565b60208082528101610b9781846136a0565b606081016138068286613032565b6138136020830185613032565b6125336040830184613032565b634e487b7160e01b600052602260045260246000fd5b60028104600182168061384a57607f821691505b60208210810361385c5761385c613820565b50919050565b60008060006060848603121561387a5761387a600080fd5b60006138868686612f86565b935050602061389786828701612f86565b925050604061317b868287016134d2565b80516000906102008401906138bd858261311e565b5060208301516138d0602086018261311e565b5060408301516138e3604086018261311e565b5060608301516138f6606086018261311e565b5060808301516139096080860182613032565b5060a083015161391c60a0860182613032565b5060c083015161392f60c0860182613032565b5060e083015161394260e0860182613032565b50610100830151613957610100860182613032565b5061012083015161396c610120860182613032565b50610140830151613981610140860182613032565b50610160830151613996610160860182613032565b506101808301516139ab610180860182613032565b506101a08301516139c06101a0860182613452565b506101c08301516137cd6101c0860182613232565b60208082528101610b9781846138a8565b634e487b7160e01b600052603260045260246000fd5b600061055b613a088381565b90565b612f06816139fc565b60808101613a228287613032565b613a2f6020830186613a0b565b613a3c6040830185613a0b565b61197d6060830184613032565b60808101613a578287613a0b565b613a646020830186613032565b613a716040830185613032565b61197d6060830184613a0b565b80516000906101c0840190613a93858261311e565b506020830151613aa6602086018261311e565b506040830151613ab9604086018261311e565b506060830151613acc606086018261311e565b506080830151613adf6080860182613032565b5060a0830151613af260a0860182613032565b5060c0830151613b0560c0860182613032565b5060e0830151613b1860e0860182613032565b50610100830151613b2d610100860182613032565b50610120830151613b42610120860182613032565b50610140830151613b57610140860182613032565b50610160830151613b6c610160860182613452565b50610180830151613b81610180860182613232565b506101a08301518482036101a086015261197d8282613072565b60208082528101610b978184613a7e565b60a08101613bba828861311e565b613bc7602083018761311e565b613bd4604083018661311e565b613be1606083018561311e565b8181036080830152612cba8184613072565b62ffffff8116612ec8565b805161055b81613bf3565b600060208284031215613c1e57613c1e600080fd5b60006125338484613bfe565b60808101613c388287613032565b613c456020830186613232565b613a3c6040830185613032565b60008060408385031215613c6857613c68600080fd5b6000613c748585612f86565b9250506020613114858286016134d2565b8051600090610140840190613c9a858261311e565b506020830151613cad602086018261311e565b506040830151613cc06040860182613032565b506060830151613cd36060860182613032565b506080830151613ce66080860182613032565b5060a0830151613cf960a0860182613032565b5060c0830151613d0c60c0860182613032565b5060e0830151613d1f60e0860182613032565b50610100830151613d34610100860182613232565b5061012083015184820361012086015261197d8282613072565b60208082528101610b978184613c85565b6000613d69825190565b613d77818560208601613046565b9290920192915050565b6000610b978284613d5f565b6000613d9b61337c84613337565b905082815260208101848484011115613db657613db6600080fd5b6133a7848285613046565b600082601f830112613dd557613dd5600080fd5b8151612533848260208601613d8d565b600060208284031215613dfa57613dfa600080fd5b815167ffffffffffffffff811115613e1457613e14600080fd5b61253384828501613dc1565b6020808252810161055b81601f81527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00602082015260400190565b60408101613e69828561311e565b610b97602083018461311e565b805161055b816130d0565b600060208284031215613e9657613e96600080fd5b60006125338484613e76565b801515612ec8565b805161055b81613ea2565b600060208284031215613eca57613eca600080fd5b60006125338484613eaa565b805161055b81612f7d565b600060208284031215613ef657613ef6600080fd5b60006125338484613ed6565b600061ffff821661055b565b612f0681613f02565b60a08101613f258287613f0e565b613f32602083018661311e565b613f3f6040830185613032565b613f4c6060830184613032565b81810360808301526000815260208101610a10565b60608101613f6f828661311e565b613813602083018561311e565b60808101613f8a828761311e565b613f97602083018661311e565b613fa46040830185613032565b61197d6060830184613232565b60006000198203613fc457613fc4613612565b5060010190565b60c08101613fd98289613032565b613fe6602083018861311e565b613ff3604083018761311e565b6140006060830186613032565b61400d6080830185613032565b612cba60a0830184613032565b61190160f01b815260020160006140318285613032565b6020820191506140418284613032565b5060200192915050565b604081016140598285613032565b81810360208301526125338184613072565b6000815461407881613836565b60018216801561408f57600181146140a4576140d4565b60ff19831686528115158202860193506140d4565b60008581526020902060005b838110156140cc578154888201526001909101906020016140b0565b838801955050505b50505092915050565b6000610b97828461406b565b60a081016140f78288613a0b565b6141046020830187613032565b6141116040830186613a0b565b61411e6060830185613032565b610a10608083018461311e56feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212209d4df6080488c965e85c8d46a748d3e9c678e134194f5c0fad6ef2903c78217b64736f6c634300080f0033a26469706673582212204b619fda80c15b4e75b8d2761286fe37fd0165cae1297695220dd54ad6154e8764736f6c634300080f0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000608cb7c3168427091f5994a45baf12083964b4a3

-----Decoded View---------------
Arg [0] : _master (address): 0x608Cb7C3168427091F5994A45Baf12083964B4A3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000608cb7c3168427091f5994a45baf12083964b4a3


Block Transaction Gas Used Reward
view all blocks sequenced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.