Sepolia Testnet

Contract

0xB184ddE3e21a3c7e7e142264a7E558836CeaCdD2
Transaction Hash
Method
Block
From
To
Open Position66004312024-08-30 13:37:36161 days ago1725025056IN
0xB184ddE3...36CeaCdD2
0 ETH0.0041985613.14505068
Open Position66004272024-08-30 13:36:48161 days ago1725025008IN
0xB184ddE3...36CeaCdD2
0 ETH0.0036026812.04389195
Open Position66004222024-08-30 13:35:48161 days ago1725024948IN
0xB184ddE3...36CeaCdD2
0 ETH0.0036347411.3798147
Open Position66004162024-08-30 13:34:24161 days ago1725024864IN
0xB184ddE3...36CeaCdD2
0 ETH0.0032908111.00129042
Open Position66004112024-08-30 13:33:12161 days ago1725024792IN
0xB184ddE3...36CeaCdD2
0 ETH0.0033334610.43653441
Open Position66004062024-08-30 13:32:12161 days ago1725024732IN
0xB184ddE3...36CeaCdD2
0 ETH0.0032813410.96963918
Open Position66004012024-08-30 13:31:12161 days ago1725024672IN
0xB184ddE3...36CeaCdD2
0 ETH0.002990019.36125664
Open Position66003962024-08-30 13:30:00161 days ago1725024600IN
0xB184ddE3...36CeaCdD2
0 ETH0.00306599.59920653
Open Position66003912024-08-30 13:29:00161 days ago1725024540IN
0xB184ddE3...36CeaCdD2
0 ETH0.003139869.83114835
Open Position66003862024-08-30 13:27:48161 days ago1725024468IN
0xB184ddE3...36CeaCdD2
0 ETH0.002780959.29680146
Open Position66003812024-08-30 13:26:36161 days ago1725024396IN
0xB184ddE3...36CeaCdD2
0 ETH0.002716029.08011375
Open Position66003762024-08-30 13:25:36161 days ago1725024336IN
0xB184ddE3...36CeaCdD2
0 ETH0.0032362310.13213682
Open Position66003712024-08-30 13:24:36161 days ago1725024276IN
0xB184ddE3...36CeaCdD2
0 ETH0.002979439.96072609
Open Position66003662024-08-30 13:23:36161 days ago1725024216IN
0xB184ddE3...36CeaCdD2
0 ETH0.003090610.33279688
Open Position66003622024-08-30 13:22:36161 days ago1725024156IN
0xB184ddE3...36CeaCdD2
0 ETH0.002814019.40807403
Open Position66003562024-08-30 13:21:24161 days ago1725024084IN
0xB184ddE3...36CeaCdD2
0 ETH0.0032063310.71928341
Open Position66003512024-08-30 13:20:00161 days ago1725024000IN
0xB184ddE3...36CeaCdD2
0 ETH0.002593198.11888303
Open Position66003462024-08-30 13:18:36161 days ago1725023916IN
0xB184ddE3...36CeaCdD2
0 ETH0.002610758.17384944
Open Position66003412024-08-30 13:17:36161 days ago1725023856IN
0xB184ddE3...36CeaCdD2
0 ETH0.002121997.09388051
Open Position66003372024-08-30 13:16:48161 days ago1725023808IN
0xB184ddE3...36CeaCdD2
0 ETH0.002274257.12060029
Open Position66003312024-08-30 13:15:36161 days ago1725023736IN
0xB184ddE3...36CeaCdD2
0 ETH0.002085836.53090507
Open Position66003272024-08-30 13:14:48161 days ago1725023688IN
0xB184ddE3...36CeaCdD2
0 ETH0.002349977.35740006
Open Position66003212024-08-30 13:13:24161 days ago1725023604IN
0xB184ddE3...36CeaCdD2
0 ETH0.002288697.16553034
Open Position66003162024-08-30 13:12:24161 days ago1725023544IN
0xB184ddE3...36CeaCdD2
0 ETH0.002575048.60912591
Open Position66003122024-08-30 13:11:36161 days ago1725023496IN
0xB184ddE3...36CeaCdD2
0 ETH0.002264737.57138239
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ClearingHouse

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 999999 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 16 : ClearingHouse.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";

import "./libraries/UniswapV2Library.sol";
import "./console.sol";

import {IMarketRegistry} from "./interfaces/IMarketRegistry.sol";
import { IClearingHouse } from "./interfaces/IClearingHouse.sol";
import { IAccountBalance } from "./interfaces/IAccountBalance.sol";
import { IVault } from "./interfaces/IVault.sol";

contract ClearingHouse is IClearingHouse, Ownable{        
    mapping(address => mapping(address => mapping(bytes32 => Position))) positionMap;       // trader => baseToken => Position

    address marketRegistry;
    address router;    
    address vault;
    address accountBalance;
    address orderBook;
    address factory;    
    address quoteToken;

    constructor() Ownable(msg.sender) {
    }

    // 유동성 풀이 존재하는지 확인
    modifier hasPool(address baseToken) {        
        require(IMarketRegistry(marketRegistry).hasPool(baseToken), "");
        _;
    }

    modifier onlyOrderBook() {        
        require(msg.sender == orderBook , "No permission");
        _;
    }

    // 초기 유동성 풀 가격 비율 설정
    function initializePool(address baseToken, uint amountBase, uint amountQuote) public onlyOwner {      
        address pool = getPool(baseToken);

        // 유동성 추가
        (,,uint liquidity) = IUniswapV2Router02(router).addLiquidity(baseToken, quoteToken, amountBase, amountQuote, 0, 0, address(this), block.timestamp);
        
        // msg.sender => baseToken => lp토큰 개수 업데이트
        IVault(vault).updateUserLP(msg.sender, pool, liquidity, true);
        emit AddLiquidity(msg.sender, baseToken, liquidity);
    }

    // usdt와 같은 가치를 가진 baseToken 개수 반환
    function getQuote(address quoteToken, address baseToken, uint quoteAmount) public view returns(uint baseAmount){
        address pool = getPool(baseToken);
                
        (address tokenA, ) = UniswapV2Library.sortTokens(quoteToken, baseToken);               
        (uint reserveA, uint reserveB, ) = IUniswapV2Pair(pool).getReserves();
        (reserveA, reserveB) = tokenA == quoteToken ? (reserveA, reserveB) : (reserveB, reserveA);

        baseAmount = UniswapV2Library.quote(quoteAmount, reserveA, reserveB);        
    }   

    //유동성 추가
    function addLiquidity (address baseToken, uint quoteAmount, uint quoteMinimum, uint baseTokenMinimum, uint deadline) public hasPool(baseToken) {         
        // unclaimed reward가 있다면 클레임
        address pool = getPool(baseToken);
        IVault(vault).claimRewards(msg.sender, pool);

       // Vault에서 msg.sender의 보증금 amountIn*2 만큼 차감 요청        
        IVault(vault).updateCollateral(msg.sender, quoteAmount*2, false);

        address _quoteToken = quoteToken;
        uint baseAmount = getQuote(_quoteToken, baseToken, quoteAmount);
        
        // 유동성 추가
        (,,uint liquidity) = IUniswapV2Router02(router).addLiquidity(_quoteToken, baseToken, quoteAmount, baseAmount, quoteMinimum, baseTokenMinimum, address(this), deadline);
        
        // msg.sender => baseToken => lp토큰 개수 업데이트          
        IVault(vault).updateUserLP(msg.sender, pool, liquidity, true);
        emit AddLiquidity(msg.sender, baseToken, liquidity);     
    }

    //유동성 제거
    function removeLiquidity (address baseToken, uint liquidity, uint quoteMinimum, uint baseTokenMinimum, uint deadline) public hasPool(baseToken) {
        // unclaimed reward가 있다면 클레임       
        address pool = getPool(baseToken);
        IVault(vault).claimRewards(msg.sender, pool);

        // msg.sender의 LPToken 보유 개수가 liquidity 보다 큰 지 확인 
        uint userLP = IVault(vault).getUserLP(msg.sender, pool);
        require(userLP >= liquidity, "Insufficient LP tokens");
                
        // 유동성 제거
        (uint amountA, ) = IUniswapV2Router02(router).removeLiquidity(quoteToken, baseToken, liquidity, quoteMinimum, baseTokenMinimum, address(this), deadline); 
        
        // msg.sender => baseToken => lp토큰 개수 업데이트        
        IVault(vault).updateUserLP(msg.sender, pool, liquidity, false);

        emit RemoveLiquidity(msg.sender, baseToken, liquidity);

        // Vault에서 msg.sender의 보증금 amountA*2 만큼 증가 요청 
        IVault(vault).updateCollateral(msg.sender, amountA*2, true);
    }

    // pool에 저장된 baseToken의 시간 가중치 가격 반환.
    function getPricecumulativeLast(address baseToken, address quoteToken) public view returns(uint priceCumulativeLast) {
        address pool = getPool(baseToken);
        (address tokenA, ) = UniswapV2Library.sortTokens(baseToken, quoteToken);
        priceCumulativeLast = tokenA == baseToken ? IUniswapV2Pair(pool).price0CumulativeLast() : IUniswapV2Pair(pool).price1CumulativeLast();
    }

    // position의 보증금 추가 입금
    function addMargin(address baseToken, bytes32 positionHash, uint amount) public {
        _updateMargin(msg.sender, baseToken, positionHash, int(amount));
    }

    // position의 보증금 업데이트
    function _updateMargin(address trader, address baseToken, bytes32 positionHash, int amount) internal {
        Position storage position = positionMap[trader][baseToken][positionHash];        

        // Vault에 있는 보증금 업데이트
        IVault(vault).updateCollateral(trader, uint(amount > 0 ? amount : -amount), amount < 0);

        // position에 있는 보증금 업데이트
        if(amount > 0)
            position.margin += uint(amount);
        else
            position.margin -= uint(-amount);
        emit UpdatePosition(trader, baseToken, positionHash, position.margin, position.positionSize, position.openNotional, position.isLong);
    }

    // 포지션 오픈
    function openPosition(address baseToken, bool isExactInput, bool isLong, uint margin, uint amountIn, uint amountOut, uint deadline) public hasPool(baseToken) {
        _openPosition(msg.sender, baseToken, isExactInput, isLong, margin, amountIn, amountOut, deadline);
    }

    // 예약 주문에 의한 포지션 오픈
    function openPositionForOrderBook(address trader, address baseToken, bool isExactInput, bool isLong, uint margin, uint amountIn, uint amountOut, uint deadline) public hasPool(baseToken) onlyOrderBook {
        _openPosition(trader, baseToken, isExactInput, isLong, margin, amountIn, amountOut, deadline);
    }

    function _openPosition(address trader, address baseToken, bool isExactInput, bool isLong, uint margin, uint amountIn, uint amountOut, uint deadline) internal {
        address pool = getPool(baseToken);
        Position memory position;        
        (position.margin, position.isLong) = (margin, isLong);

        // Vault에 있는 보증금 차감
        IVault(vault).updateCollateral(trader, margin, false);
        {             
            address[] memory path = new address[](2);
            
            // Long: USDT => baseToken, short: baseToken => USDT
            (path[0], path[1]) = isLong ? (quoteToken, baseToken) : (baseToken, quoteToken);
            (uint[] memory amounts, uint liquidityFee, uint orderBookFee) = isLong ? _buy(trader, path, isExactInput, amountIn, amountOut, deadline) : _sell(trader, path, isExactInput, amountIn, amountOut, deadline);
            
            (position.positionSize, position.openNotional) = isLong ? (amounts[1], amounts[0]) : (amounts[0], amounts[1]);            
            require(position.openNotional <= margin * 100, "Exceeded the maximum allowed leverage");

            // 수수료 누적
            IVault(vault).setCumulativeTransactionFee(pool, liquidityFee);
            if(orderBookFee > 0) {
                IVault(vault).updateCollateral(tx.origin, orderBookFee, true);
            }
        }                    

        // feePerLiquidityCumulative값 Valut에 요청
        uint feePerLiquidityCumulative = IVault(vault).getCumulativeTransactionFee(pool);  

        // Long or Short 포지션 규모 누적
        IAccountBalance(accountBalance).setOpenInterest(baseToken, int256(position.positionSize), isLong);

        bytes32 positionHash = getpositionHash(trader, baseToken, feePerLiquidityCumulative);
        _updatePosition(position, trader, baseToken, positionHash );
    }

    // 포지션 오픈 or 포지션 종료 시 현재 시점의 누적 토큰 가격, timestamp, 누적 fundingRate 갱신
    function _updatePosition(Position memory position, address trader, address baseToken, bytes32 positionHash) internal {
        // closePosition 시 평균 가격을 측정하기 위한 priceCumulative, block.timestamp 저장
        position.priceCumulativeLast = getPricecumulativeLast(baseToken,quoteToken);
        position.openPositionTimestamp = uint32(block.timestamp % 2**32);    

        // fundingRateCumulative값 AccountBalanace에 요청
        position.fundingRateCumulativeLast = position.isLong ? 
            IAccountBalance(accountBalance).cumulativeLongFundingRates(baseToken) : IAccountBalance(accountBalance).cumulativeShortFundingRates(baseToken);        

        positionMap[trader][baseToken][positionHash] = position;
        emit UpdatePosition(trader, baseToken, positionHash, position.margin, position.positionSize, position.openNotional, position.isLong);
    }

    // 사용자에 의해 호출되는 포지션 종료
    function closePosition (address baseToken, bytes32 positionHash, uint closePercent, uint slippageAdjustedAmount, uint deadline) public {
        _closePosition(msg.sender, baseToken, positionHash, closePercent, slippageAdjustedAmount, deadline);
    }

    function closePositionBatch (address[] memory baseTokens, bytes32[] memory positionHashs, uint[] memory slippageAdjustedAmounts, uint deadline) public {
        require(baseTokens.length == positionHashs.length && positionHashs.length == slippageAdjustedAmounts.length, "Array lengths do not match");

        for(uint i = 0; i < baseTokens.length; i++ ) {
            _closePosition(msg.sender, baseTokens[i], positionHashs[i], 100, slippageAdjustedAmounts[i], deadline);
        }
    }

    // 예약 주문에 의해 호출되는 포지션 종료
    function closePositionForOrderBook (address trader, address baseToken, bytes32 positionHash, uint closePercent, uint slippageAdjustedAmount, uint deadline) public onlyOrderBook{
        _closePosition(trader, baseToken, positionHash, closePercent, slippageAdjustedAmount, deadline);
    }

    // 사용자 또는 청산자에 의해 호출되는 포지션 종료
    function _closePosition(address trader, address baseToken, bytes32 positionHash, uint closePercent, uint slippageAdjustedAmount, uint deadline) internal {
        address pool = IMarketRegistry(marketRegistry).getPool(baseToken);
        Position memory position = positionMap[trader][baseToken][positionHash];        

        if(closePercent == 100) 
            emit ClosePosition(trader, baseToken, positionHash, position.margin, position.positionSize, position.openNotional, position.isLong);        
        
        // fundingPayment AccountBalance에 계산 요청         
        int256 fundingPayment = IAccountBalance(accountBalance).calculateFundingPayment(position, baseToken, pool);
        {            
            address[] memory path = new address[](2);
            // Long: baseToken => USDT, Short: USDT => baseToken
            (path[0], path[1]) = position.isLong ? (baseToken, quoteToken ) : (quoteToken, baseToken);
            
            uint closePositionSize = closePercent * position.positionSize / 100;

            (uint[] memory amounts, uint liquidityFee, uint orderBookFee) = position.isLong ? _sell(trader, path, true, closePositionSize, slippageAdjustedAmount, deadline) : _buy(trader, path, false, slippageAdjustedAmount, closePositionSize, deadline);
            
            // 수수료 적립
            IVault(vault).setCumulativeTransactionFee(pool, liquidityFee);
            if(orderBookFee > 0) {
                IVault(vault).updateCollateral(tx.origin, orderBookFee, true);
            }

            if(!position.isLong) {
                (amounts[0], amounts[1]) = (amounts[1], amounts[0]); // amounts[0]: closePositionSize, amounts[1]: closeNotional                             
            }            

            // 포지션의 크기에 비례하는 수익 또는 손해, 펀딩비 정산
            _settlePNL(position, trader, baseToken, positionHash, amounts[0], amounts[1], fundingPayment);

            // 종료된 포지션의 크기만큼 Long, Short OI 감소
            IAccountBalance(accountBalance).setOpenInterest(baseToken, -int256(closePositionSize), position.isLong);              
        }        

        // 모든 계약이 청산되면 Close, 일부 남아 있으면 Update
        if(position.positionSize == 0) {
            delete positionMap[trader][baseToken][positionHash];
        } else {
            _updatePosition(position, trader, baseToken, positionHash);
        }
    }

    // 손익 계산 및 정산
    function _settlePNL(Position memory position, address trader, address baseToken, bytes32 positionHash, uint closePositionSize, uint closeNotional, int256 fundingPayment) private {                
        
        uint closePercent = closePositionSize * 100 / position.positionSize;
        uint refundMargin = position.margin * closePercent / 100;        
        int PNL = int256(refundMargin) + fundingPayment;
        uint256 leverage = position.openNotional * closePercent / 100;

        position.margin -= refundMargin;
        position.positionSize -= closePositionSize;
        position.openNotional -= leverage;

        bool isLong = position.isLong;        
        if(isLong) {
            PNL += int256(closeNotional) - int256(leverage);
        } else {
            PNL += int256(leverage) - int256(closeNotional);
        }
        
        IVault(vault).updateCollateral(trader, PNL > 0 ? uint(PNL) : uint(-PNL), PNL > 0);
        
        emit SettlePNL(trader, baseToken, positionHash, refundMargin, closePositionSize, closeNotional, isLong, PNL);
    }

    // base => quote, quote => base 모두 quote로 지불
    // quoteToken => baseToken(롱포지션 오픈 or 숏포지션 종료)
    function _buy(address trader, address[] memory path, bool isExactInput, uint amountIn, uint amountOut, uint deadline) private returns(uint[] memory amounts, uint liquidityFee, uint orderBookFee){           
        (uint amountInMaximum, uint amountOutMinimum) = (amountIn, amountOut);
        bool isOrderBook = msg.sender == orderBook;
        uint fee;

        if(isExactInput) {  
            // 0.03%~0.05% 만큼 baseToken이 적게 나오도록 함
            liquidityFee = amountIn * 3 / 1e4;
            orderBookFee = isOrderBook ? amountIn * 2 / 1e4 : 0;            
            fee = liquidityFee + orderBookFee; 
            amounts = IUniswapV2Router02(router).swapExactTokensForTokens(amountIn - fee, amountOutMinimum, path, address(this), deadline);                
        } else {                        
            // 지불한 금액의 0.03%~0.05% 만큼 USDT를 추가로 지불하게 함
            amounts = IUniswapV2Router02(router).swapTokensForExactTokens(amountOut, amountInMaximum, path, address(this), deadline);            
            liquidityFee = amounts[0] * 3 / 1e4;
            orderBookFee = isOrderBook ? amounts[0] * 2 / 1e4 : 0;            
            fee = liquidityFee + orderBookFee; 
        }        
        emit Buy(trader, path[1], amounts[0], amounts[1]);
        amounts[0] += fee;
    }

    // baseToken => quoteToken(롱포지션 종료 or 숏포지션 오픈)
    function _sell(address trader, address[] memory path, bool isExactInput, uint amountIn, uint amountOut, uint deadline) private returns(uint[] memory amounts, uint liquidityFee, uint orderBookFee) {           
        (uint amountInMaximum, uint amountOutMinimum) = (amountIn, amountOut);
        bool isOrderBook = msg.sender == orderBook;
        uint fee;

        if(isExactInput) {
            // 0.03%~0.05%만큼 USDT가 적게 나오도록 함
            amounts = IUniswapV2Router02(router).swapExactTokensForTokens(amountIn, amountOutMinimum, path, address(this), deadline);
            liquidityFee = amounts[1] * 3 / 1e4;
            orderBookFee = isOrderBook ? amounts[1] * 2 / 1e4 : 0;            
            fee = liquidityFee + orderBookFee; 
        } else {
            // 0.03%~0.05%만큼 USDT가 더 나오도록 baseToken을 더 요구함
            liquidityFee = amountOut * 3 / 1e4;
            orderBookFee = isOrderBook ? amountOut * 2 / 1e4 : 0;            
            fee = liquidityFee + orderBookFee; 
            amounts = IUniswapV2Router02(router).swapTokensForExactTokens(amountOut + fee, amountInMaximum, path, address(this), deadline);
        }        
        emit Sell(trader, path[0], amounts[0], amounts[1]);
        amounts[1] -= fee;
    }

    // 다수의 포지션 동시에 정리
    function liquidateBatch (address[] memory traders, address[] memory baseTokens, bytes32[] memory positionHashs) public {
        require((traders.length == baseTokens.length) && (baseTokens.length == positionHashs.length), "");

        for(uint i = 0; i < traders.length; i++) {
            liquidate(traders[i], baseTokens[i], positionHashs[i]);
        }
    }

    // 하나의 포지션 정리
    function liquidate(address trader, address baseToken, bytes32 positionHash) public {
        // accountBalance에 trader, baseToken, positionHash가 청산 포지션인지 확인
        Position storage position = positionMap[trader][baseToken][positionHash];

        address pool = getPool(baseToken);
        
        bool isLiquidatable = IAccountBalance(accountBalance).checkLiquidation(position, baseToken, pool);
        // require로 작성 시 liquidateBatch 함수로 포지션 정리 시 1개라도 청산 조건에 만족하지 못 할 경우 모두 취소되기 때문에 if문으로 return
        if(!isLiquidatable) {
            return;
        }

        uint clearingFee = position.margin / 100;
        position.margin -= clearingFee;

        uint slippageAdjustedAmount = position.isLong ? 0 : type(uint256).max;
        _closePosition(trader, baseToken, positionHash, 100, slippageAdjustedAmount, block.timestamp);

        //vault에 msg.sender의 보증금 clearingFee만큼 증가 요청
         IVault(vault).updateCollateral(msg.sender, clearingFee, true);
    }

    // router가 virtual token에 접근할 수 있도록 approve
    function approve(address _token) public onlyOwner {
        require(router != address(0), "");
        (bool success, ) = _token.call(abi.encodeWithSignature("approve(address,uint256)", router, type(uint256).max));
        require(success);
    }

    function setMarketRegistry(address _marketRegistry) public onlyOwner {
        marketRegistry = _marketRegistry;
    }

    function setRouter(address _router) public onlyOwner {
        router = _router;
    }

    function setVault(address _vault) public onlyOwner {
        vault = _vault;
    } 

    function setAccountBalance(address _accountBalance) public onlyOwner {
        accountBalance = _accountBalance;
    }

    function setOrderBook(address _orderBook) public onlyOwner {
        orderBook = _orderBook;
    }

    function setQuoteToken(address _quete) public onlyOwner {
        quoteToken = _quete;
    }

    function getMarketRegistry() public view returns(address) {
        return marketRegistry;
    }

    function getRouter() public view returns(address) {
        return router;
    }

    function getVault() public view returns(address) {
        return vault;
    }

    function getAccountBalance() public view returns(address) {
        return accountBalance;
    }

    function getOrderBook() public view returns(address) {
        return orderBook;
    }

    function getPool(address baseToken) internal view returns(address) {
        return IMarketRegistry(marketRegistry).getPool(baseToken);
    }

    function getPosition(address trader, address baseToken, bytes32 positionHash) public view returns(Position memory) {
        return positionMap[trader][baseToken][positionHash];
    }

    function getpositionHash(address trader, address baseToken, uint salt) public pure returns(bytes32) {
        return keccak256(abi.encodePacked(trader, baseToken, salt));
    }
}

File 2 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 16 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 4 of 16 : IUniswapV2Factory.sol
pragma solidity >=0.5.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}

File 5 of 16 : IUniswapV2Pair.sol
pragma solidity >=0.5.0;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

File 6 of 16 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

File 7 of 16 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

File 8 of 16 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS =
        0x000000000000000000636F6e736F6c652e6c6f67;

    function _sendLogPayloadImplementation(bytes memory payload) internal view {
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            pop(
                staticcall(
                    gas(),
                    consoleAddress,
                    add(payload, 32),
                    mload(payload),
                    0,
                    0
                )
            )
        }
    }

    function _castToPure(
      function(bytes memory) internal view fnIn
    ) internal pure returns (function(bytes memory) pure fnOut) {
        assembly {
            fnOut := fnIn
        }
    }

    function _sendLogPayload(bytes memory payload) internal pure {
        _castToPure(_sendLogPayloadImplementation)(payload);
    }

    function log() internal pure {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }
    function logInt(int256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
    }

    function logUint(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function logString(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint256 p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
    }

    function log(string memory p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint256 p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
    }

    function log(uint256 p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
    }

    function log(uint256 p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
    }

    function log(uint256 p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
    }

    function log(string memory p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
    }

    function log(bool p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint256 p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
    }

    function log(address p0, string memory p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint256 p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
    }

    function log(uint256 p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
    }

    function log(uint256 p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
    }

    function log(uint256 p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
    }

    function log(bool p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
    }

    function log(address p0, uint256 p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint256 p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint256 p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint256 p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint256 p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint256 p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal pure {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

File 9 of 16 : IAccountBalance.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import "./IClearingHouse.sol";

interface IAccountBalance {
    // 함수
    function setKeeper(address newKeeper) external;
    function getMarkPrice(address baseToken) external view returns (uint256);
    function setIndexPrice(address baseToken, uint256 price) external;
    function getIndexPrice(address baseToken) external view returns (uint256);
    function setOpenInterest(address baseToken, int256 positionSize, bool isLong) external;
    function getLongOpenInterest(address baseToken) external view returns (uint256);
    function getShortOpenInterest(address baseToken) external view returns (uint256);
    function checkLiquidation(
        IClearingHouse.Position memory position,
        address baseToken,
        address poolAddress
    ) external view returns (bool);
    function calculateFundingPayment(
        IClearingHouse.Position memory position,
        address baseToken,
        address poolAddress
    ) external view returns (int256);

    // 상태 변수에 대한 getter 함수들
    function lastFundingTimes(address baseToken) external view returns (uint256);
    function cumulativeLongFundingRates(address baseToken) external view returns (int256);
    function cumulativeShortFundingRates(address baseToken) external view returns (int256);
    function userLongFundingPayments(address baseToken, address user) external view returns (int256);
    function userShortFundingPayments(address baseToken, address user) external view returns (int256);
}

File 10 of 16 : IClearingHouse.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";

import "../libraries/UniswapV2Library.sol";
import "../MarketRegistry.sol";

interface IClearingHouse {
    struct Position {
        uint256 margin;                    
        uint256 positionSize;               
        uint256 openNotional;               
        bool isLong;                        
        uint256 priceCumulativeLast;        
        uint32 openPositionTimestamp;      
        int256 fundingRateCumulativeLast;  
    }

    event AddLiquidity(address indexed provider, address indexed baseToken, uint liquidity);
    event RemoveLiquidity(address indexed provider, address indexed baseToken, uint liquidity);
    event UpdatePosition(address indexed trader, address indexed baseToken, bytes32 positionHash, uint margin, uint positionSize, uint openNotional, bool isLong);
    event ClosePosition(address indexed trader, address indexed baseToken, bytes32 positionHash, uint margin, uint positionSize, uint openNotional, bool isLong);
    event SettlePNL(address indexed trader, address indexed baseToken, bytes32 positionHash, uint margin, uint positionSize, uint closeNotional, bool isLong, int PNL);
    event Buy(address indexed trader, address indexed baseToken, uint amountIn, uint amountOut);
    event Sell(address indexed trader, address indexed baseToken, uint amountIn, uint amountOut);

    function initializePool(address baseToken, uint amountBase, uint amountQuote) external ;

    function getQuote(address quoteToken, address baseToken, uint quoteAmount) external view returns(uint baseAmount);
    function getPricecumulativeLast(address baseToken, address quoteToken) external view returns(uint priceCumulativeLast) ;

    function addLiquidity (address baseToken, uint quoteAmount, uint quoteMinimum, uint baseTokenMinimum, uint deadline) external ;
    function removeLiquidity (address baseToken, uint liquidity, uint quoteMinimum, uint baseTokenMinimum, uint deadline) external  ;

    function openPosition(address baseToken, bool isExactInput, bool isLong, uint margin, uint amountIn, uint amountOut, uint deadline) external;
    function openPositionForOrderBook(address trader, address baseToken, bool isExactInput, bool isLong, uint margin, uint amountIn, uint amountOut, uint deadline) external;

    function closePosition (address baseToken, bytes32 positionHash, uint amountIn, uint amountOut, uint deadline) external;
    function closePositionBatch (address[] memory baseTokens, bytes32[] memory positionHashs, uint[] memory slippageAdjustedAmounts, uint deadline) external;
    function closePositionForOrderBook (address trader, address baseToken, bytes32 positionHash, uint closePercent, uint slippageAdjustedAmount, uint deadline) external;

    function liquidateBatch (address[] memory traders, address[] memory baseTokens, bytes32[] memory positionHashs) external ;
    function liquidate(address trader, address baseToken, bytes32 positionHash) external ;

    function approve(address _token) external;

    function setMarketRegistry(address _marketRegistry) external;
    function setRouter(address _router) external;
    function setVault(address _vault) external;
    function setQuoteToken(address _quete) external;
    function setOrderBook(address _orderBook) external;    

    function getMarketRegistry() external view returns(address) ;
    function getRouter() external view returns(address); 
    function getVault() external view returns(address);
    function getOrderBook() external view returns(address);
    function getPosition(address trader, address baseToken, bytes32 positionHash) external view returns(Position memory);

    function getpositionHash(address trader, address baseToken, uint salt) external pure returns(bytes32);
}

File 11 of 16 : IERC20.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0;

interface IERC20 {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);
}

File 12 of 16 : IMarketRegistry.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

interface IMarketRegistry {
    event CreatePool(address poolAddress, address baseToken, address quoteToken);
    
    function createPool(string memory _name, string memory _symbol, uint8 _decimals) external;

    function setClearingHouse(address _clearingHouse) external;
    function setFactory(address _factory) external;
    function setQuoteToken(address _quoteToken) external;

    function setFeeRatio(address _baseToken, uint24 _feeRatio) external;
    function setPriceImpactLimit(address _baseToken, uint24 _priceImpactLimit) external;

    function getAllPools() external view returns(address[] memory);
    function getAllBaseTokens() external view returns(address[] memory);
    function getAllPoolsLength() external view returns(uint);

    function getClearingHouse() external view returns(address);
    function getFactory() external view returns(address);
    function getQuoteToken() external view returns(address);

    function getFeeRatio(address baseToken) external view returns(uint24);
    function getPriceImpactLimit(address baseToken) external view returns(uint24);
    
    function getPool(address _baseToken) external view returns(address);
    function hasPool(address _baseToken) external view returns(bool);
}

File 13 of 16 : IVault.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.26;

interface IVault {
    struct LiquidityProvider {
        uint256 cumulativeTransactionFeeLast;   // 진입 시점까지 쌓여있는 수수료
        uint256 userLP;     // 사용자 보유 LP 토큰 개수
    }

    /// @notice Emitted when trader deposit collateral into vault
    /// @param collateralToken The address of token deposited
    /// @param trader The address of trader
    /// @param amount The amount of token deposited
    event Deposited(address indexed collateralToken, address indexed trader, uint256 amount);

    /// @notice Emitted when trader withdraw collateral from vault
    /// @param collateralToken The address of token withdrawn
    /// @param trader The address of trader
    /// @param amount The amount of token withdrawn
    event Withdrawn(address indexed collateralToken, address indexed trader, uint256 amount);

    /// @notice Emitted when clearingHouse is changed
    /// @param clearingHouse The address of clearingHouse
    event ClearingHouseChanged(address indexed clearingHouse);

    /// @notice Emitted when trader claim fee
    /// @param trader The address of trader
    /// @param poolAddress The address of liquidity pool address
    /// @param amount The amount of token claimed
    event Claimed(address indexed trader, address indexed poolAddress, uint256 amount);

    /// @notice Get settlement token decimals
    /// @return decimals The decimals of settlement token
    function decimals() external view returns (uint8 decimals);

    /// @notice Deposit collateral into vault
    /// @param amount The amount of the token to deposit
    function deposit(uint256 amount) external;

    /// @notice Deposit the collateral token for other account
    /// @param to The address of the account to deposit to
    /// @param amount The amount of the token to deposit
    function depositFor(
        address to,
        uint256 amount
    ) external;

    /// @notice Withdraw collateral from vault
    /// @param amount The amount of the token to withdraw
    function withdraw(uint256 amount) external;

    /// @notice Withdraw all free collateral from vault
    function withdrawAll() external;

    /// @notice Update the balance of Vault of the specified collateral token and trader
    /// @param trader The address of the trader
    /// @param amount The amount of the token to update
    /// @param isPlus Is the amount positive(true) or negative(false)
    function updateCollateral(address trader, uint256 amount, bool isPlus) external;

    /// @notice Get the total collateral value of trader
    /// @param trader The address of the trader
    /// @return totalCollateral total collateral
    function getTotalCollateral(address trader) external view returns (uint256 totalCollateral);

    /// @notice Get the used collateral value of trader
    /// @param trader The address of the trader
    /// @return useCollateral used collateral
    function getUseCollateral(address trader) external view returns (uint256 useCollateral);

    /// @notice Get the free collateral value denominated in the settlement token of the specified trader
    /// @param trader The address of the trader
    /// @return freeCollateral the value (in settlement token's decimals) of free collateral available
    ///         for withdraw or opening new positions or orders)
    function getFreeCollateral(address trader) external view returns (uint256 freeCollateral);

    /// @notice Update the balance of LP token of the trader
    /// @param trader The address of the trader
    /// @param pool The address of the liquidity pool contract
    /// @param amount The amount of the token to update
    /// @param isPlus Is the amount positive(true) or negative(false)
    function updateUserLP(address trader, address pool, uint256 amount, bool isPlus) external;

    /// @notice Claim the reward of the trader
    /// @param trader The address of the trader
    /// @param pool The address of the liquidity pool contract
    function claimRewards(address trader, address pool) external;

    /// @notice Set the cumulative transaction fee per 1LP of liquidity pool
    /// @param pool The address of the liquidity pool contract
    /// @param fee transaction fee per 1LP
    function setCumulativeTransactionFee(address pool, uint256 fee) external;

    /// @notice Get the cumulative transaction fee per 1LP of liquidity pool
    /// @param pool The address of the liquidity pool contract
    /// @return cumulativeTransactionFee cumulative transaction fee per 1LP
    function getCumulativeTransactionFee(address pool) external  view returns (uint256 cumulativeTransactionFee);

    /// @notice Get the trader's LP token balance.
    /// @param trader The address of the trader
    /// @param pool The address of the liquidity pool contract
    function getUserLP(address trader, address pool) external view returns(uint256);

    /// @notice Get the trader's LP token balance.
    /// @param trader The address of the trader
    /// @param pool The address of the liquidity pool contract
    function getUnclaimedRewards(address trader, address pool) external view returns(uint256);

}

File 14 of 16 : UniswapV2Library.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;


library UniswapV2Library {

    // returns sorted token addresses, used to handle return values from pairs sorted in this order
    function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
        require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES');
        (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS');
    }

    // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
    function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
        require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
        require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
        amountB = amountA * reserveB / reserveA;
    }

    // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
        require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
        require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
        
        uint numerator = amountIn * reserveOut;
        uint denominator = reserveIn + amountIn;
        amountOut = numerator / denominator;
    }

    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
        require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT');
        require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
        uint numerator = reserveIn * amountOut;
        uint denominator = reserveOut - amountOut;
        amountIn = (numerator / denominator) + 1;
    }
}

File 15 of 16 : MarketRegistry.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 < 0.9.0;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol";
import "./VirtualToken.sol";
import "./interfaces/IMarketRegistry.sol";

/*
- 유동성 풀 생성
- 유동성 풀 데이터 관리
- vBTC 주소 입력하면 풀 주소 반환
*/

contract MarketRegistry is IMarketRegistry, Ownable{
    address clearingHouse;
    address factory;
    address quoteToken;

    mapping(address => address) public pool;
    address[] public allPools;
    address[] public allBaseTokens;

    mapping(address => uint24) feeRatio;
    mapping(address => uint24) priceImpactLimit;

    constructor(address _factory) Ownable(msg.sender) {
        factory = _factory;
    }

    function createPool(string memory _name, string memory _symbol, uint8 _decimals) public onlyOwner{    
        if(quoteToken == address(0)) {
            VirtualToken vt = new VirtualToken("vUSDT", "USDT", 6);
            quoteToken = address(vt);
            vt.transfer(clearingHouse, vt.balanceOf(address(this)));
        }
        VirtualToken vt = new VirtualToken(_name, _symbol, _decimals);
        vt.transfer(clearingHouse, vt.balanceOf(address(this)));

        address baseToken = address(vt);

        address poolAddress = IUniswapV2Factory(factory).createPair(baseToken, quoteToken);

        pool[baseToken] = poolAddress;
        allPools.push(poolAddress);
        allBaseTokens.push(baseToken);

        setFeeRatio(baseToken, 3e2);
        setPriceImpactLimit(baseToken, 1e4);
       
        emit CreatePool(poolAddress, baseToken, quoteToken);
    }

    function setClearingHouse(address _clearingHouse) public onlyOwner {
        clearingHouse = _clearingHouse;
    }

    function setFactory(address _factory) public onlyOwner {
        factory = _factory;
    }

    function setQuoteToken(address _quoteToken) public onlyOwner {
        quoteToken = _quoteToken;
    }

    // 1% = 1e4, 100% = 1e6
    function setFeeRatio(address _baseToken, uint24 _feeRatio) public onlyOwner{
        require(_feeRatio >= 1e2 && _feeRatio <= 1e3, "");  // 0.01% <= feeRatio <= 0.1%
        feeRatio[_baseToken] = _feeRatio;
    }

    function setPriceImpactLimit(address _baseToken, uint24 _priceImpactLimit) public onlyOwner{
        require(_priceImpactLimit >= 5e3 && _priceImpactLimit <= 5e4, "");  // 0.5% <= feeRatio <= 5.0%
        priceImpactLimit[_baseToken] = _priceImpactLimit;
    }

    function hasPool(address _baseToken) public view returns(bool) {
        return getPool(_baseToken) != address(0);
    }   

    function getPool(address _baseToken) public view returns(address) {
        return pool[_baseToken];
    }     

    function getAllPools() public view returns(address[] memory) {
        return allPools;
    }

    function getAllBaseTokens() public view returns(address[] memory) {
        return allBaseTokens;
    }

    function getAllPoolsLength() public view returns(uint) {
        return allPools.length;
    }

    function getClearingHouse() public view returns(address) {
        return clearingHouse;
    }

    function getFactory() public view returns(address) {
        return factory;
    }

    function getQuoteToken() public view returns(address) {
        return quoteToken;
    }

    function getFeeRatio(address _baseToken) public view returns(uint24) {
        return feeRatio[_baseToken];
    }

    function getPriceImpactLimit(address _baseToken) public view returns(uint24) {
        return priceImpactLimit[_baseToken];
    }
}

File 16 of 16 : VirtualToken.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

import "./interfaces/IERC20.sol";

abstract contract ERC20 {
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed spender, uint256 amount);


    string public name;
    string public symbol;
    uint8 public immutable decimals;

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;


    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}


/*
    - Uniswap Pool에 들어갈 가상 토큰 발행
    - 가스비 절약을 위해 추가 발행 없이 클리어링 하우스에 최대한 민팅
*/
contract VirtualToken is ERC20  {    
    constructor(string memory _name, string memory _symbol, uint8 _decimals) ERC20(_name, _symbol, _decimals) {
        _mint(msg.sender, type(uint256).max);
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 999999
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"bytes32","name":"positionHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"openNotional","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"}],"name":"ClosePosition","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"Sell","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"bytes32","name":"positionHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"closeNotional","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"},{"indexed":false,"internalType":"int256","name":"PNL","type":"int256"}],"name":"SettlePNL","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"trader","type":"address"},{"indexed":true,"internalType":"address","name":"baseToken","type":"address"},{"indexed":false,"internalType":"bytes32","name":"positionHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"margin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"positionSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"openNotional","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLong","type":"bool"}],"name":"UpdatePosition","type":"event"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"},{"internalType":"uint256","name":"quoteMinimum","type":"uint256"},{"internalType":"uint256","name":"baseTokenMinimum","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bytes32","name":"positionHash","type":"bytes32"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addMargin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bytes32","name":"positionHash","type":"bytes32"},{"internalType":"uint256","name":"closePercent","type":"uint256"},{"internalType":"uint256","name":"slippageAdjustedAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"closePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"baseTokens","type":"address[]"},{"internalType":"bytes32[]","name":"positionHashs","type":"bytes32[]"},{"internalType":"uint256[]","name":"slippageAdjustedAmounts","type":"uint256[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"closePositionBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bytes32","name":"positionHash","type":"bytes32"},{"internalType":"uint256","name":"closePercent","type":"uint256"},{"internalType":"uint256","name":"slippageAdjustedAmount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"closePositionForOrderBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAccountBalance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMarketRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOrderBook","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bytes32","name":"positionHash","type":"bytes32"}],"name":"getPosition","outputs":[{"components":[{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"positionSize","type":"uint256"},{"internalType":"uint256","name":"openNotional","type":"uint256"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"priceCumulativeLast","type":"uint256"},{"internalType":"uint32","name":"openPositionTimestamp","type":"uint32"},{"internalType":"int256","name":"fundingRateCumulativeLast","type":"int256"}],"internalType":"struct IClearingHouse.Position","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"quoteToken","type":"address"}],"name":"getPricecumulativeLast","outputs":[{"internalType":"uint256","name":"priceCumulativeLast","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"quoteToken","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"quoteAmount","type":"uint256"}],"name":"getQuote","outputs":[{"internalType":"uint256","name":"baseAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"salt","type":"uint256"}],"name":"getpositionHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"amountBase","type":"uint256"},{"internalType":"uint256","name":"amountQuote","type":"uint256"}],"name":"initializePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bytes32","name":"positionHash","type":"bytes32"}],"name":"liquidate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"traders","type":"address[]"},{"internalType":"address[]","name":"baseTokens","type":"address[]"},{"internalType":"bytes32[]","name":"positionHashs","type":"bytes32[]"}],"name":"liquidateBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bool","name":"isExactInput","type":"bool"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"openPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"bool","name":"isExactInput","type":"bool"},{"internalType":"bool","name":"isLong","type":"bool"},{"internalType":"uint256","name":"margin","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"openPositionForOrderBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"quoteMinimum","type":"uint256"},{"internalType":"uint256","name":"baseTokenMinimum","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_accountBalance","type":"address"}],"name":"setAccountBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_marketRegistry","type":"address"}],"name":"setMarketRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_orderBook","type":"address"}],"name":"setOrderBook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_quete","type":"address"}],"name":"setQuoteToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_router","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052348015600f57600080fd5b503380603557604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b603c816041565b506091565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b614770806100a06000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80639144b6da11610104578063c0d78655116100a2578063d857970411610071578063d8579704146104a7578063daea85c5146104ba578063ee9ff183146104cd578063f2fde38b146104e057600080fd5b8063c0d7865514610443578063c515ee2314610456578063c66b8ed214610469578063cc0b40011461048757600080fd5b8063ac6fdffb116100de578063ac6fdffb146103e1578063b0f479a1146103f4578063b248c4ef14610412578063b84ecf6f1461043057600080fd5b80639144b6da146103a85780639a1598c8146103bb578063a554f4cb146103ce57600080fd5b80631cfb886d1161017c578063715018a61161014b578063715018a614610351578063791a8402146103595780638d928af81461036c5780638da5cb5b1461038a57600080fd5b80631cfb886d146102d957806367797f70146102ec5780636817031b146102ff5780636896fabf1461031257600080fd5b806312eb6ab1116101b857806312eb6ab11461028d57806313928082146102a057806314812995146102b3578063199387cc146102c657600080fd5b8063055f765e146101df5780630b1fcb66146102655780631124367d1461027a575b600080fd5b6102526101ed366004613c87565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085811b8216602084015284901b166034820152604881018290526000906068016040516020818303038152906040528051906020012090509392505050565b6040519081526020015b60405180910390f35b610278610273366004613cd6565b6104f3565b005b610278610288366004613d44565b6105e6565b61027861029b366004613c87565b6105fb565b6102786102ae366004613d44565b610802565b6102786102c1366004613efe565b610cf0565b6102786102d4366004613f92565b610db2565b6102786102e7366004613f92565b610e01565b6102786102fa366004613fb6565b610e50565b61027861030d366004613f92565b610ee7565b60055473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161025c565b610278610f36565b61027861036736600461400f565b610f4a565b60045473ffffffffffffffffffffffffffffffffffffffff1661032c565b60005473ffffffffffffffffffffffffffffffffffffffff1661032c565b6102786103b6366004613d44565b610f5b565b6102786103c9366004613f92565b611373565b6102526103dc366004614044565b6113c2565b6102786103ef36600461400f565b6114fe565b60035473ffffffffffffffffffffffffffffffffffffffff1661032c565b60065473ffffffffffffffffffffffffffffffffffffffff1661032c565b61027861043e36600461407d565b6116d6565b610278610451366004613f92565b6117bc565b610252610464366004613c87565b61180b565b60025473ffffffffffffffffffffffffffffffffffffffff1661032c565b61049a610495366004613c87565b611918565b60405161025c9190614172565b6102786104b5366004613f92565b6119f7565b6102786104c8366004613f92565b611a46565b6102786104db3660046141c7565b611bce565b6102786104ee366004613f92565b611d3e565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808a16600483015289921690631246dbf590602401602060405180830381865afa158015610563573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105879190614247565b6105cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044015b60405180910390fd5b6105dc3389898989898989611da2565b5050505050505050565b6105f433868686868661238f565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152600160209081526040808320938616835292815282822084835290529081209061064184612aa6565b6005546040517f604d28f400000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063604d28f4906106a190869089908790600401614264565b602060405180830381865afa1580156106be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e29190614247565b9050806106f157505050505050565b82546000906107029060649061433c565b9050808460000160008282546107189190614350565b9091555050600384015460009060ff16610752577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610755565b60005b90506107668888886064854261238f565b600480546040517f0363a1610000000000000000000000000000000000000000000000000000000081523392810192909252602482018490526001604483015273ffffffffffffffffffffffffffffffffffffffff1690630363a16190606401600060405180830381600087803b1580156107e057600080fd5b505af11580156107f4573d6000803e3d6000fd5b505050505050505050505050565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816600483015287921690631246dbf590602401602060405180830381865afa158015610872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190614247565b6108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60006108e187612aa6565b600480546040517ff1e42ccd000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff8084166024840152929350919091169063f1e42ccd90604401600060405180830381600087803b15801561095b57600080fd5b505af115801561096f573d6000803e3d6000fd5b5050600480546040517f679375ce000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff85811660248401526000945016915063679375ce90604401602060405180830381865afa1580156109ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a119190614363565b905086811015610a7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e73756666696369656e74204c5020746f6b656e730000000000000000000060448201526064016105c3565b6003546008546040517fbaa2abde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201528a82166024820152604481018a905260648101899052608481018890523060a482015260c48101879052600092919091169063baa2abde9060e40160408051808303816000875af1158015610b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b43919061437c565b50600480546040517f7a83c1f7000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff8681166024840152604483018c9052600060648401529293509190911690637a83c1f790608401600060405180830381600087803b158015610bcc57600080fd5b505af1158015610be0573d6000803e3d6000fd5b50506040518a815273ffffffffffffffffffffffffffffffffffffffff8c1692503391507fd8ae9b9ba89e637bcb66a69ac91e8f688018e81d6f92c57e02226425c8efbdf69060200160405180910390a360045473ffffffffffffffffffffffffffffffffffffffff16630363a16133610c5b8460026143a0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9092166004830152602482015260016044820152606401600060405180830381600087803b158015610ccd57600080fd5b505af1158015610ce1573d6000803e3d6000fd5b50505050505050505050505050565b81518351148015610d02575080518251145b610d42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60005b8351811015610dac57610da4848281518110610d6357610d636143b7565b6020026020010151848381518110610d7d57610d7d6143b7565b6020026020010151848481518110610d9757610d976143b7565b60200260200101516105fb565b600101610d45565b50505050565b610dba612b41565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610e09612b41565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60065473ffffffffffffffffffffffffffffffffffffffff163314610ed1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f207065726d697373696f6e0000000000000000000000000000000000000060448201526064016105c3565b610edf86868686868661238f565b505050505050565b610eef612b41565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610f3e612b41565b610f486000612b94565b565b610f5633848484612c09565b505050565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816600483015287921690631246dbf590602401602060405180830381865afa158015610fcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fef9190614247565b61102f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b600061103a87612aa6565b600480546040517ff1e42ccd000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff8084166024840152929350919091169063f1e42ccd90604401600060405180830381600087803b1580156110b457600080fd5b505af11580156110c8573d6000803e3d6000fd5b505060045473ffffffffffffffffffffffffffffffffffffffff169150630363a1619050336110f88960026143a0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9092166004830152602482015260006044820152606401600060405180830381600087803b15801561116a57600080fd5b505af115801561117e573d6000803e3d6000fd5b505060085473ffffffffffffffffffffffffffffffffffffffff169150600090506111aa828a8a61180b565b6003546040517fe8e3370000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528c81166024830152604482018c905260648201849052608482018b905260a482018a90523060c483015260e482018990529293506000929091169063e8e3370090610104016060604051808303816000875af1158015611254573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127891906143e6565b600480546040517f7a83c1f7000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff89811660248401526044830184905260016064840152929550919091169250637a83c1f79150608401600060405180830381600087803b15801561130257600080fd5b505af1158015611316573d6000803e3d6000fd5b505060405183815273ffffffffffffffffffffffffffffffffffffffff8d1692503391507f668256213e6a9a0247adc238fcbf44cc6b98921642fca93479c5dc38736608379060200160405180910390a350505050505050505050565b61137b612b41565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000806113ce84612aa6565b905060006113dc8585612dbb565b5090508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611486578173ffffffffffffffffffffffffffffffffffffffff16635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa15801561145d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114819190614363565b6114f5565b8173ffffffffffffffffffffffffffffffffffffffff16635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f59190614363565b95945050505050565b611506612b41565b600061151184612aa6565b6003546008546040517fe8e3370000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529182166024820152604481018790526064810186905260006084820181905260a482018190523060c48301524260e483015293945091169063e8e3370090610104016060604051808303816000875af11580156115bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115df91906143e6565b600480546040517f7a83c1f7000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff87811660248401526044830184905260016064840152929550919091169250637a83c1f79150608401600060405180830381600087803b15801561166957600080fd5b505af115801561167d573d6000803e3d6000fd5b505060405183815273ffffffffffffffffffffffffffffffffffffffff881692503391507f668256213e6a9a0247adc238fcbf44cc6b98921642fca93479c5dc3873660837906020015b60405180910390a35050505050565b825184511480156116e8575081518351145b61174e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4172726179206c656e6774687320646f206e6f74206d6174636800000000000060448201526064016105c3565b60005b84518110156105f4576117b433868381518110611770576117706143b7565b602002602001015186848151811061178a5761178a6143b7565b602002602001015160648786815181106117a6576117a66143b7565b60200260200101518761238f565b600101611751565b6117c4612b41565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008061181784612aa6565b905060006118258686612dbb565b5090506000808373ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189a9190614437565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff1691508773ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146118f95780826118fc565b81815b909250905061190c868383612f3f565b98975050505050505050565b6119606040518060e0016040528060008152602001600081526020016000815260200160001515815260200160008152602001600063ffffffff168152602001600081525090565b5073ffffffffffffffffffffffffffffffffffffffff9283166000908152600160208181526040808420959096168352938452848220928252918352839020835160e081018552815481529181015492820192909252600282015492810192909252600381015460ff161515606083015260048101546080830152600581015463ffffffff1660a08301526006015460c082015290565b6119ff612b41565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611a4e612b41565b60035473ffffffffffffffffffffffffffffffffffffffff16611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60035460405173ffffffffffffffffffffffffffffffffffffffff91821660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6044820152600091831690606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905251611b7a9190614487565b6000604051808303816000865af19150503d8060008114611bb7576040519150601f19603f3d011682016040523d82523d6000602084013e611bbc565b606091505b5050905080611bca57600080fd5b5050565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808a16600483015289921690631246dbf590602401602060405180830381865afa158015611c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c629190614247565b611ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60065473ffffffffffffffffffffffffffffffffffffffff163314611d23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f207065726d697373696f6e0000000000000000000000000000000000000060448201526064016105c3565b611d338989898989898989611da2565b505050505050505050565b611d46612b41565b73ffffffffffffffffffffffffffffffffffffffff8116611d96576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024016105c3565b611d9f81612b94565b50565b6000611dad88612aa6565b9050611df76040518060e0016040528060008152602001600081526020016000815260200160001515815260200160008152602001600063ffffffff168152602001600081525090565b8615156060820152858152600480546040517f0363a16100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d8116938201939093526024810189905260006044820152911690630363a16190606401600060405180830381600087803b158015611e7f57600080fd5b505af1158015611e93573d6000803e3d6000fd5b506000925060029150611ea39050565b604051908082528060200260200182016040528015611ecc578160200160208202803683370190505b50905087611ef4576008548a9073ffffffffffffffffffffffffffffffffffffffff16611f0f565b60085473ffffffffffffffffffffffffffffffffffffffff168a5b82600081518110611f2257611f226143b7565b6020026020010183600181518110611f3c57611f3c6143b7565b73ffffffffffffffffffffffffffffffffffffffff938416602091820292909201015291169052600080808a611f7f57611f7a8e858e8c8c8c613089565b611f8d565b611f8d8e858e8c8c8c613408565b9250925092508a611fd35782600081518110611fab57611fab6143b7565b602002602001015183600181518110611fc657611fc66143b7565b602002602001015161200a565b82600181518110611fe657611fe66143b7565b602002602001015183600081518110612001576120016143b7565b60200260200101515b6040870152602086015261201f8a60646143a0565b856040015111156120b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f457863656564656420746865206d6178696d756d20616c6c6f776564206c657660448201527f657261676500000000000000000000000000000000000000000000000000000060648201526084016105c3565b600480546040517f406f300900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116938201939093526024810185905291169063406f300990604401600060405180830381600087803b15801561212857600080fd5b505af115801561213c573d6000803e3d6000fd5b5050505060008111156121dc57600480546040517f0363a1610000000000000000000000000000000000000000000000000000000081523292810192909252602482018390526001604483015273ffffffffffffffffffffffffffffffffffffffff1690630363a16190606401600060405180830381600087803b1580156121c357600080fd5b505af11580156121d7573d6000803e3d6000fd5b505050505b5050600480546040517fd763637c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811693820193909352600094509116915063d763637c90602401602060405180830381865afa158015612255573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122799190614363565b60055460208401516040517f840c82de00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e8116600483015260248201929092528b15156044820152929350169063840c82de90606401600060405180830381600087803b1580156122fc57600080fd5b505af1158015612310573d6000803e3d6000fd5b5050505060006123818c8c846040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085811b8216602084015284901b166034820152604881018290526000906068016040516020818303038152906040528051906020012090509392505050565b90506107f4838d8d84613770565b6002546040517fbbe4f6db00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152600092169063bbe4f6db90602401602060405180830381865afa158015612400573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242491906144b6565b73ffffffffffffffffffffffffffffffffffffffff8089166000908152600160208181526040808420948c1684529381528383208a8452815291839020835160e081018552815481529181015492820192909252600282015492810192909252600381015460ff161515606083015260048101546080830152600581015463ffffffff1660a08301526006015460c0820152909150606485900361253f57805160208083015160408085015160608087015183518d81529586019690965291840192909252820152901515608082015273ffffffffffffffffffffffffffffffffffffffff80891691908a16907f2cbdc2c8e4fe199d732c8f7fdfcb932f5a5191a4b557c81dde4704d8944aced59060a00160405180910390a35b6005546040517fa328618200000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff169063a32861829061259a9085908c9088906004016144d3565b602060405180830381865afa1580156125b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125db9190614363565b604080516002808252606082018352929350600092909160208301908036833701905050905082606001516126295760085473ffffffffffffffffffffffffffffffffffffffff1689612645565b600854899073ffffffffffffffffffffffffffffffffffffffff165b82600081518110612658576126586143b7565b6020026020010183600181518110612672576126726143b7565b602002602001018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152508273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505050600060648460200151896126ef91906143a0565b6126f9919061433c565b90506000806000866060015161271d576127188e8660008d888e613408565b61272c565b61272c8e866001878e8e613089565b600480546040517f406f300900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81169382019390935260248101859052949750929550909350169063406f300990604401600060405180830381600087803b1580156127aa57600080fd5b505af11580156127be573d6000803e3d6000fd5b50505050600081111561285e57600480546040517f0363a1610000000000000000000000000000000000000000000000000000000081523292810192909252602482018390526001604483015273ffffffffffffffffffffffffffffffffffffffff1690630363a16190606401600060405180830381600087803b15801561284557600080fd5b505af1158015612859573d6000803e3d6000fd5b505050505b86606001516128da578260018151811061287a5761287a6143b7565b602002602001015183600081518110612895576128956143b7565b6020026020010151846000815181106128b0576128b06143b7565b60200260200101856001815181106128ca576128ca6143b7565b6020908102919091010191909152525b61291d878f8f8f876000815181106128f4576128f46143b7565b60200260200101518860018151811061290f5761290f6143b7565b60200260200101518c613a34565b60055473ffffffffffffffffffffffffffffffffffffffff1663840c82de8e6129458761456a565b60608b01516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff9093166004840152602483019190915215156044820152606401600060405180830381600087803b1580156129bf57600080fd5b505af11580156129d3573d6000803e3d6000fd5b5050505050505050508160200151600003612a9a5773ffffffffffffffffffffffffffffffffffffffff808a166000908152600160208181526040808420948d1684529381528383208b84529052918120818155918201819055600282018190556003820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600482018190556005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000169055600690910155611d33565b611d33828a8a8a613770565b6002546040517fbbe4f6db00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152600092169063bbe4f6db90602401602060405180830381865afa158015612b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3b91906144b6565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f48576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016105c3565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260016020908152604080832087851684528252808320868452909152812060045490921690630363a1619087908513612c6757612c628561456a565b612c69565b845b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152600085126044820152606401600060405180830381600087803b158015612cdd57600080fd5b505af1158015612cf1573d6000803e3d6000fd5b505050506000821315612d1d5781816000016000828254612d1291906145a2565b90915550612d3f9050565b612d268261456a565b816000016000828254612d399190614350565b90915550505b8054600182015460028301546003840154604080518881526020810195909552840192909252606083015260ff161515608082015273ffffffffffffffffffffffffffffffffffffffff85811691908716907fa0da177c50de7b9d2ef872a12ba0253ac6a13b8c2987a94198f6c09cebbe65669060a0016116c7565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612e79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f556e697377617056324c6962726172793a204944454e544943414c5f4144445260448201527f455353455300000000000000000000000000000000000000000000000000000060648201526084016105c3565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610612eb3578284612eb6565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216612f38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f41444452455353000060448201526064016105c3565b9250929050565b6000808411612fd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4160448201527f4d4f554e5400000000000000000000000000000000000000000000000000000060648201526084016105c3565b600083118015612fe05750600082115b61306c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4c60448201527f495155494449545900000000000000000000000000000000000000000000000060648201526084016105c3565b8261307783866143a0565b613081919061433c565b949350505050565b60065460609060009081908690869073ffffffffffffffffffffffffffffffffffffffff163314838a1561320a57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed17398b858f308d6040518663ffffffff1660e01b815260040161311a9594939291906145b5565b6000604051808303816000875af1158015613139573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261317f9190810190614641565b965061271087600181518110613197576131976143b7565b602002602001015160036131ab91906143a0565b6131b5919061433c565b9550816131c35760006131f7565b612710876001815181106131d9576131d96143b7565b602002602001015160026131ed91906143a0565b6131f7919061433c565b945061320385876145a2565b905061330b565b6127106132188a60036143a0565b613222919061433c565b955081613230576000613248565b61271061323e8a60026143a0565b613248919061433c565b945061325485876145a2565b60035490915073ffffffffffffffffffffffffffffffffffffffff16638803dbee61327f838c6145a2565b868f308d6040518663ffffffff1660e01b81526004016132a39594939291906145b5565b6000604051808303816000875af11580156132c2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526133089190810190614641565b96505b8b60008151811061331e5761331e6143b7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167fa082022e93cfcd9f1da5f9236718053910f7e840da080c789c7845698dc032ff89600081518110613387576133876143b7565b60200260200101518a6001815181106133a2576133a26143b7565b60200260200101516040516133c1929190918252602082015260400190565b60405180910390a380876001815181106133dd576133dd6143b7565b602002602001018181516133f19190614350565b915081815250505050505096509650969350505050565b60065460609060009081908690869073ffffffffffffffffffffffffffffffffffffffff163314838a1561353b576127106134448b60036143a0565b61344e919061433c565b95508161345c576000613474565b61271061346a8b60026143a0565b613474919061433c565b945061348085876145a2565b60035490915073ffffffffffffffffffffffffffffffffffffffff166338ed17396134ab838d614350565b858f308d6040518663ffffffff1660e01b81526004016134cf9594939291906145b5565b6000604051808303816000875af11580156134ee573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526135349190810190614641565b965061368a565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638803dbee8a868f308d6040518663ffffffff1660e01b815260040161359e9594939291906145b5565b6000604051808303816000875af11580156135bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526136039190810190614641565b96506127108760008151811061361b5761361b6143b7565b6020026020010151600361362f91906143a0565b613639919061433c565b95508161364757600061367b565b6127108760008151811061365d5761365d6143b7565b6020026020010151600261367191906143a0565b61367b919061433c565b945061368785876145a2565b90505b8b60018151811061369d5761369d6143b7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f89f5adc174562e07c9c9b1cae7109bbecb21cf9d1b2847e550042b8653c54a0e89600081518110613706576137066143b7565b60200260200101518a600181518110613721576137216143b7565b6020026020010151604051613740929190918252602082015260400190565b60405180910390a3808760008151811061375c5761375c6143b7565b602002602001018181516133f191906145a2565b60085461379490839073ffffffffffffffffffffffffffffffffffffffff166113c2565b60808501526137a8640100000000426146d7565b63ffffffff1660a08501526060840151613855576005546040517fef57ff2d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529091169063ef57ff2d90602401602060405180830381865afa15801561382c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138509190614363565b6138e9565b6005546040517f1959f77800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015290911690631959f77890602401602060405180830381865afa1580156138c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138e99190614363565b60c0850190815273ffffffffffffffffffffffffffffffffffffffff80851660008181526001602081815260408084209589168085529582528084208885528252928390208a51808255918b0151928101839055838b01516002820181905560608c01516003830180548215157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911617905560808d0151600484015560a08d015160058401805463ffffffff9092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090921691909117905597516006909201919091559251949593947fa0da177c50de7b9d2ef872a12ba0253ac6a13b8c2987a94198f6c09cebbe656694613a26948994929091909485526020850193909352604084019190915260608301521515608082015260a00190565b60405180910390a350505050565b6020870151600090613a478560646143a0565b613a51919061433c565b905060006064828a60000151613a6791906143a0565b613a71919061433c565b90506000613a7f84836146eb565b905060006064848c60400151613a9591906143a0565b613a9f919061433c565b9050828b600001818151613ab39190614350565b90525060208b018051889190613aca908390614350565b90525060408b018051829190613ae1908390614350565b90525060608b01518015613b0a57613af98288614713565b613b0390846146eb565b9250613b21565b613b148783614713565b613b1e90846146eb565b92505b60045473ffffffffffffffffffffffffffffffffffffffff16630363a1618c60008613613b5657613b518661456a565b613b58565b855b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152600086136044820152606401600060405180830381600087803b158015613bcc57600080fd5b505af1158015613be0573d6000803e3d6000fd5b5050604080518c8152602081018890529081018b9052606081018a9052831515608082015260a0810186905273ffffffffffffffffffffffffffffffffffffffff808e1693508e1691507f2129da0bc7433471df98bc9551d98bfda0f2c2eff005eeca7759217c73fa5aa99060c00160405180910390a3505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611d9f57600080fd5b600080600060608486031215613c9c57600080fd5b8335613ca781613c65565b92506020840135613cb781613c65565b929592945050506040919091013590565b8015158114611d9f57600080fd5b600080600080600080600060e0888a031215613cf157600080fd5b8735613cfc81613c65565b96506020880135613d0c81613cc8565b95506040880135613d1c81613cc8565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080600080600060a08688031215613d5c57600080fd5b8535613d6781613c65565b97602087013597506040870135966060810135965060800135945092505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613dfe57613dfe613d88565b604052919050565b600067ffffffffffffffff821115613e2057613e20613d88565b5060051b60200190565b600082601f830112613e3b57600080fd5b8135613e4e613e4982613e06565b613db7565b8082825260208201915060208360051b860101925085831115613e7057600080fd5b602085015b83811015613e96578035613e8881613c65565b835260209283019201613e75565b5095945050505050565b600082601f830112613eb157600080fd5b8135613ebf613e4982613e06565b8082825260208201915060208360051b860101925085831115613ee157600080fd5b602085015b83811015613e96578035835260209283019201613ee6565b600080600060608486031215613f1357600080fd5b833567ffffffffffffffff811115613f2a57600080fd5b613f3686828701613e2a565b935050602084013567ffffffffffffffff811115613f5357600080fd5b613f5f86828701613e2a565b925050604084013567ffffffffffffffff811115613f7c57600080fd5b613f8886828701613ea0565b9150509250925092565b600060208284031215613fa457600080fd5b8135613faf81613c65565b9392505050565b60008060008060008060c08789031215613fcf57600080fd5b8635613fda81613c65565b95506020870135613fea81613c65565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60008060006060848603121561402457600080fd5b833561402f81613c65565b95602085013595506040909401359392505050565b6000806040838503121561405757600080fd5b823561406281613c65565b9150602083013561407281613c65565b809150509250929050565b6000806000806080858703121561409357600080fd5b843567ffffffffffffffff8111156140aa57600080fd5b6140b687828801613e2a565b945050602085013567ffffffffffffffff8111156140d357600080fd5b6140df87828801613ea0565b935050604085013567ffffffffffffffff8111156140fc57600080fd5b8501601f8101871361410d57600080fd5b803561411b613e4982613e06565b8082825260208201915060208360051b85010192508983111561413d57600080fd5b6020840193505b8284101561415f578335825260209384019390910190614144565b9699959850959660600135955050505050565b60e08101612b3b82848051825260208101516020830152604081015160408301526060810151151560608301526080810151608083015263ffffffff60a08201511660a083015260c081015160c08301525050565b600080600080600080600080610100898b0312156141e457600080fd5b88356141ef81613c65565b975060208901356141ff81613c65565b9650604089013561420f81613cc8565b9550606089013561421f81613cc8565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b60006020828403121561425957600080fd5b8151613faf81613cc8565b835481526001840154602082015260028401546040820152600384015460ff161515606082015260048401546080820152600584015463ffffffff1660a0820152600684015460c082015273ffffffffffffffffffffffffffffffffffffffff83811660e083015282166101008201526101208101613081565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261434b5761434b6142de565b500490565b81810381811115612b3b57612b3b61430d565b60006020828403121561437557600080fd5b5051919050565b6000806040838503121561438f57600080fd5b505080516020909101519092909150565b8082028115828204841417612b3b57612b3b61430d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000806000606084860312156143fb57600080fd5b5050815160208301516040909301519094929350919050565b80516dffffffffffffffffffffffffffff8116811461443257600080fd5b919050565b60008060006060848603121561444c57600080fd5b61445584614414565b925061446360208501614414565b9150604084015163ffffffff8116811461447c57600080fd5b809150509250925092565b6000825160005b818110156144a8576020818601810151858301520161448e565b506000920191825250919050565b6000602082840312156144c857600080fd5b8151613faf81613c65565b610120810161452982868051825260208101516020830152604081015160408301526060810151151560608301526080810151608083015263ffffffff60a08201511660a083015260c081015160c08301525050565b73ffffffffffffffffffffffffffffffffffffffff841660e083015273ffffffffffffffffffffffffffffffffffffffff8316610100830152949350505050565b60007f8000000000000000000000000000000000000000000000000000000000000000820361459b5761459b61430d565b5060000390565b80820180821115612b3b57612b3b61430d565b600060a0820187835286602084015260a0604084015280865180835260c08501915060208801925060005b8181101561461457835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016145e0565b505073ffffffffffffffffffffffffffffffffffffffff9590951660608401525050608001529392505050565b60006020828403121561465357600080fd5b815167ffffffffffffffff81111561466a57600080fd5b8201601f8101841361467b57600080fd5b8051614689613e4982613e06565b8082825260208201915060208360051b8501019250868311156146ab57600080fd5b6020840193505b828410156146cd5783518252602093840193909101906146b2565b9695505050505050565b6000826146e6576146e66142de565b500690565b808201828112600083128015821682158216171561470b5761470b61430d565b505092915050565b81810360008312801583831316838312821617156147335761473361430d565b509291505056fea26469706673582212205a9c8b0ba66eef68deea99ce8b92a4a12900709811af8b780c8f90316adca54164736f6c634300081a0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101da5760003560e01c80639144b6da11610104578063c0d78655116100a2578063d857970411610071578063d8579704146104a7578063daea85c5146104ba578063ee9ff183146104cd578063f2fde38b146104e057600080fd5b8063c0d7865514610443578063c515ee2314610456578063c66b8ed214610469578063cc0b40011461048757600080fd5b8063ac6fdffb116100de578063ac6fdffb146103e1578063b0f479a1146103f4578063b248c4ef14610412578063b84ecf6f1461043057600080fd5b80639144b6da146103a85780639a1598c8146103bb578063a554f4cb146103ce57600080fd5b80631cfb886d1161017c578063715018a61161014b578063715018a614610351578063791a8402146103595780638d928af81461036c5780638da5cb5b1461038a57600080fd5b80631cfb886d146102d957806367797f70146102ec5780636817031b146102ff5780636896fabf1461031257600080fd5b806312eb6ab1116101b857806312eb6ab11461028d57806313928082146102a057806314812995146102b3578063199387cc146102c657600080fd5b8063055f765e146101df5780630b1fcb66146102655780631124367d1461027a575b600080fd5b6102526101ed366004613c87565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085811b8216602084015284901b166034820152604881018290526000906068016040516020818303038152906040528051906020012090509392505050565b6040519081526020015b60405180910390f35b610278610273366004613cd6565b6104f3565b005b610278610288366004613d44565b6105e6565b61027861029b366004613c87565b6105fb565b6102786102ae366004613d44565b610802565b6102786102c1366004613efe565b610cf0565b6102786102d4366004613f92565b610db2565b6102786102e7366004613f92565b610e01565b6102786102fa366004613fb6565b610e50565b61027861030d366004613f92565b610ee7565b60055473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161025c565b610278610f36565b61027861036736600461400f565b610f4a565b60045473ffffffffffffffffffffffffffffffffffffffff1661032c565b60005473ffffffffffffffffffffffffffffffffffffffff1661032c565b6102786103b6366004613d44565b610f5b565b6102786103c9366004613f92565b611373565b6102526103dc366004614044565b6113c2565b6102786103ef36600461400f565b6114fe565b60035473ffffffffffffffffffffffffffffffffffffffff1661032c565b60065473ffffffffffffffffffffffffffffffffffffffff1661032c565b61027861043e36600461407d565b6116d6565b610278610451366004613f92565b6117bc565b610252610464366004613c87565b61180b565b60025473ffffffffffffffffffffffffffffffffffffffff1661032c565b61049a610495366004613c87565b611918565b60405161025c9190614172565b6102786104b5366004613f92565b6119f7565b6102786104c8366004613f92565b611a46565b6102786104db3660046141c7565b611bce565b6102786104ee366004613f92565b611d3e565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808a16600483015289921690631246dbf590602401602060405180830381865afa158015610563573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105879190614247565b6105cc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044015b60405180910390fd5b6105dc3389898989898989611da2565b5050505050505050565b6105f433868686868661238f565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff8084166000908152600160209081526040808320938616835292815282822084835290529081209061064184612aa6565b6005546040517f604d28f400000000000000000000000000000000000000000000000000000000815291925060009173ffffffffffffffffffffffffffffffffffffffff9091169063604d28f4906106a190869089908790600401614264565b602060405180830381865afa1580156106be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106e29190614247565b9050806106f157505050505050565b82546000906107029060649061433c565b9050808460000160008282546107189190614350565b9091555050600384015460009060ff16610752577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610755565b60005b90506107668888886064854261238f565b600480546040517f0363a1610000000000000000000000000000000000000000000000000000000081523392810192909252602482018490526001604483015273ffffffffffffffffffffffffffffffffffffffff1690630363a16190606401600060405180830381600087803b1580156107e057600080fd5b505af11580156107f4573d6000803e3d6000fd5b505050505050505050505050565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816600483015287921690631246dbf590602401602060405180830381865afa158015610872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190614247565b6108d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60006108e187612aa6565b600480546040517ff1e42ccd000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff8084166024840152929350919091169063f1e42ccd90604401600060405180830381600087803b15801561095b57600080fd5b505af115801561096f573d6000803e3d6000fd5b5050600480546040517f679375ce000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff85811660248401526000945016915063679375ce90604401602060405180830381865afa1580156109ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a119190614363565b905086811015610a7d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f496e73756666696369656e74204c5020746f6b656e730000000000000000000060448201526064016105c3565b6003546008546040517fbaa2abde00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201528a82166024820152604481018a905260648101899052608481018890523060a482015260c48101879052600092919091169063baa2abde9060e40160408051808303816000875af1158015610b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b43919061437c565b50600480546040517f7a83c1f7000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff8681166024840152604483018c9052600060648401529293509190911690637a83c1f790608401600060405180830381600087803b158015610bcc57600080fd5b505af1158015610be0573d6000803e3d6000fd5b50506040518a815273ffffffffffffffffffffffffffffffffffffffff8c1692503391507fd8ae9b9ba89e637bcb66a69ac91e8f688018e81d6f92c57e02226425c8efbdf69060200160405180910390a360045473ffffffffffffffffffffffffffffffffffffffff16630363a16133610c5b8460026143a0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9092166004830152602482015260016044820152606401600060405180830381600087803b158015610ccd57600080fd5b505af1158015610ce1573d6000803e3d6000fd5b50505050505050505050505050565b81518351148015610d02575080518251145b610d42576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60005b8351811015610dac57610da4848281518110610d6357610d636143b7565b6020026020010151848381518110610d7d57610d7d6143b7565b6020026020010151848481518110610d9757610d976143b7565b60200260200101516105fb565b600101610d45565b50505050565b610dba612b41565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610e09612b41565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60065473ffffffffffffffffffffffffffffffffffffffff163314610ed1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f207065726d697373696f6e0000000000000000000000000000000000000060448201526064016105c3565b610edf86868686868661238f565b505050505050565b610eef612b41565b600480547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610f3e612b41565b610f486000612b94565b565b610f5633848484612c09565b505050565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808816600483015287921690631246dbf590602401602060405180830381865afa158015610fcb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fef9190614247565b61102f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b600061103a87612aa6565b600480546040517ff1e42ccd000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff8084166024840152929350919091169063f1e42ccd90604401600060405180830381600087803b1580156110b457600080fd5b505af11580156110c8573d6000803e3d6000fd5b505060045473ffffffffffffffffffffffffffffffffffffffff169150630363a1619050336110f88960026143a0565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9092166004830152602482015260006044820152606401600060405180830381600087803b15801561116a57600080fd5b505af115801561117e573d6000803e3d6000fd5b505060085473ffffffffffffffffffffffffffffffffffffffff169150600090506111aa828a8a61180b565b6003546040517fe8e3370000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85811660048301528c81166024830152604482018c905260648201849052608482018b905260a482018a90523060c483015260e482018990529293506000929091169063e8e3370090610104016060604051808303816000875af1158015611254573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127891906143e6565b600480546040517f7a83c1f7000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff89811660248401526044830184905260016064840152929550919091169250637a83c1f79150608401600060405180830381600087803b15801561130257600080fd5b505af1158015611316573d6000803e3d6000fd5b505060405183815273ffffffffffffffffffffffffffffffffffffffff8d1692503391507f668256213e6a9a0247adc238fcbf44cc6b98921642fca93479c5dc38736608379060200160405180910390a350505050505050505050565b61137b612b41565b600680547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6000806113ce84612aa6565b905060006113dc8585612dbb565b5090508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611486578173ffffffffffffffffffffffffffffffffffffffff16635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa15801561145d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114819190614363565b6114f5565b8173ffffffffffffffffffffffffffffffffffffffff16635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f59190614363565b95945050505050565b611506612b41565b600061151184612aa6565b6003546008546040517fe8e3370000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff88811660048301529182166024820152604481018790526064810186905260006084820181905260a482018190523060c48301524260e483015293945091169063e8e3370090610104016060604051808303816000875af11580156115bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115df91906143e6565b600480546040517f7a83c1f7000000000000000000000000000000000000000000000000000000008152339281019290925273ffffffffffffffffffffffffffffffffffffffff87811660248401526044830184905260016064840152929550919091169250637a83c1f79150608401600060405180830381600087803b15801561166957600080fd5b505af115801561167d573d6000803e3d6000fd5b505060405183815273ffffffffffffffffffffffffffffffffffffffff881692503391507f668256213e6a9a0247adc238fcbf44cc6b98921642fca93479c5dc3873660837906020015b60405180910390a35050505050565b825184511480156116e8575081518351145b61174e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4172726179206c656e6774687320646f206e6f74206d6174636800000000000060448201526064016105c3565b60005b84518110156105f4576117b433868381518110611770576117706143b7565b602002602001015186848151811061178a5761178a6143b7565b602002602001015160648786815181106117a6576117a66143b7565b60200260200101518761238f565b600101611751565b6117c4612b41565b600380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008061181784612aa6565b905060006118258686612dbb565b5090506000808373ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611876573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189a9190614437565b506dffffffffffffffffffffffffffff1691506dffffffffffffffffffffffffffff1691508773ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146118f95780826118fc565b81815b909250905061190c868383612f3f565b98975050505050505050565b6119606040518060e0016040528060008152602001600081526020016000815260200160001515815260200160008152602001600063ffffffff168152602001600081525090565b5073ffffffffffffffffffffffffffffffffffffffff9283166000908152600160208181526040808420959096168352938452848220928252918352839020835160e081018552815481529181015492820192909252600282015492810192909252600381015460ff161515606083015260048101546080830152600581015463ffffffff1660a08301526006015460c082015290565b6119ff612b41565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611a4e612b41565b60035473ffffffffffffffffffffffffffffffffffffffff16611aa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60035460405173ffffffffffffffffffffffffffffffffffffffff91821660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6044820152600091831690606401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b30000000000000000000000000000000000000000000000000000000017905251611b7a9190614487565b6000604051808303816000865af19150503d8060008114611bb7576040519150601f19603f3d011682016040523d82523d6000602084013e611bbc565b606091505b5050905080611bca57600080fd5b5050565b6002546040517f1246dbf500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808a16600483015289921690631246dbf590602401602060405180830381865afa158015611c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c629190614247565b611ca2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600060248201526044016105c3565b60065473ffffffffffffffffffffffffffffffffffffffff163314611d23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f207065726d697373696f6e0000000000000000000000000000000000000060448201526064016105c3565b611d338989898989898989611da2565b505050505050505050565b611d46612b41565b73ffffffffffffffffffffffffffffffffffffffff8116611d96576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024016105c3565b611d9f81612b94565b50565b6000611dad88612aa6565b9050611df76040518060e0016040528060008152602001600081526020016000815260200160001515815260200160008152602001600063ffffffff168152602001600081525090565b8615156060820152858152600480546040517f0363a16100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8d8116938201939093526024810189905260006044820152911690630363a16190606401600060405180830381600087803b158015611e7f57600080fd5b505af1158015611e93573d6000803e3d6000fd5b506000925060029150611ea39050565b604051908082528060200260200182016040528015611ecc578160200160208202803683370190505b50905087611ef4576008548a9073ffffffffffffffffffffffffffffffffffffffff16611f0f565b60085473ffffffffffffffffffffffffffffffffffffffff168a5b82600081518110611f2257611f226143b7565b6020026020010183600181518110611f3c57611f3c6143b7565b73ffffffffffffffffffffffffffffffffffffffff938416602091820292909201015291169052600080808a611f7f57611f7a8e858e8c8c8c613089565b611f8d565b611f8d8e858e8c8c8c613408565b9250925092508a611fd35782600081518110611fab57611fab6143b7565b602002602001015183600181518110611fc657611fc66143b7565b602002602001015161200a565b82600181518110611fe657611fe66143b7565b602002602001015183600081518110612001576120016143b7565b60200260200101515b6040870152602086015261201f8a60646143a0565b856040015111156120b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f457863656564656420746865206d6178696d756d20616c6c6f776564206c657660448201527f657261676500000000000000000000000000000000000000000000000000000060648201526084016105c3565b600480546040517f406f300900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116938201939093526024810185905291169063406f300990604401600060405180830381600087803b15801561212857600080fd5b505af115801561213c573d6000803e3d6000fd5b5050505060008111156121dc57600480546040517f0363a1610000000000000000000000000000000000000000000000000000000081523292810192909252602482018390526001604483015273ffffffffffffffffffffffffffffffffffffffff1690630363a16190606401600060405180830381600087803b1580156121c357600080fd5b505af11580156121d7573d6000803e3d6000fd5b505050505b5050600480546040517fd763637c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811693820193909352600094509116915063d763637c90602401602060405180830381865afa158015612255573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122799190614363565b60055460208401516040517f840c82de00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e8116600483015260248201929092528b15156044820152929350169063840c82de90606401600060405180830381600087803b1580156122fc57600080fd5b505af1158015612310573d6000803e3d6000fd5b5050505060006123818c8c846040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606085811b8216602084015284901b166034820152604881018290526000906068016040516020818303038152906040528051906020012090509392505050565b90506107f4838d8d84613770565b6002546040517fbbe4f6db00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152600092169063bbe4f6db90602401602060405180830381865afa158015612400573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242491906144b6565b73ffffffffffffffffffffffffffffffffffffffff8089166000908152600160208181526040808420948c1684529381528383208a8452815291839020835160e081018552815481529181015492820192909252600282015492810192909252600381015460ff161515606083015260048101546080830152600581015463ffffffff1660a08301526006015460c0820152909150606485900361253f57805160208083015160408085015160608087015183518d81529586019690965291840192909252820152901515608082015273ffffffffffffffffffffffffffffffffffffffff80891691908a16907f2cbdc2c8e4fe199d732c8f7fdfcb932f5a5191a4b557c81dde4704d8944aced59060a00160405180910390a35b6005546040517fa328618200000000000000000000000000000000000000000000000000000000815260009173ffffffffffffffffffffffffffffffffffffffff169063a32861829061259a9085908c9088906004016144d3565b602060405180830381865afa1580156125b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125db9190614363565b604080516002808252606082018352929350600092909160208301908036833701905050905082606001516126295760085473ffffffffffffffffffffffffffffffffffffffff1689612645565b600854899073ffffffffffffffffffffffffffffffffffffffff165b82600081518110612658576126586143b7565b6020026020010183600181518110612672576126726143b7565b602002602001018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152508273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152505050600060648460200151896126ef91906143a0565b6126f9919061433c565b90506000806000866060015161271d576127188e8660008d888e613408565b61272c565b61272c8e866001878e8e613089565b600480546040517f406f300900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8e81169382019390935260248101859052949750929550909350169063406f300990604401600060405180830381600087803b1580156127aa57600080fd5b505af11580156127be573d6000803e3d6000fd5b50505050600081111561285e57600480546040517f0363a1610000000000000000000000000000000000000000000000000000000081523292810192909252602482018390526001604483015273ffffffffffffffffffffffffffffffffffffffff1690630363a16190606401600060405180830381600087803b15801561284557600080fd5b505af1158015612859573d6000803e3d6000fd5b505050505b86606001516128da578260018151811061287a5761287a6143b7565b602002602001015183600081518110612895576128956143b7565b6020026020010151846000815181106128b0576128b06143b7565b60200260200101856001815181106128ca576128ca6143b7565b6020908102919091010191909152525b61291d878f8f8f876000815181106128f4576128f46143b7565b60200260200101518860018151811061290f5761290f6143b7565b60200260200101518c613a34565b60055473ffffffffffffffffffffffffffffffffffffffff1663840c82de8e6129458761456a565b60608b01516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff9093166004840152602483019190915215156044820152606401600060405180830381600087803b1580156129bf57600080fd5b505af11580156129d3573d6000803e3d6000fd5b5050505050505050508160200151600003612a9a5773ffffffffffffffffffffffffffffffffffffffff808a166000908152600160208181526040808420948d1684529381528383208b84529052918120818155918201819055600282018190556003820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055600482018190556005820180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000169055600690910155611d33565b611d33828a8a8a613770565b6002546040517fbbe4f6db00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152600092169063bbe4f6db90602401602060405180830381865afa158015612b17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3b91906144b6565b92915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f48576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016105c3565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260016020908152604080832087851684528252808320868452909152812060045490921690630363a1619087908513612c6757612c628561456a565b612c69565b845b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152600085126044820152606401600060405180830381600087803b158015612cdd57600080fd5b505af1158015612cf1573d6000803e3d6000fd5b505050506000821315612d1d5781816000016000828254612d1291906145a2565b90915550612d3f9050565b612d268261456a565b816000016000828254612d399190614350565b90915550505b8054600182015460028301546003840154604080518881526020810195909552840192909252606083015260ff161515608082015273ffffffffffffffffffffffffffffffffffffffff85811691908716907fa0da177c50de7b9d2ef872a12ba0253ac6a13b8c2987a94198f6c09cebbe65669060a0016116c7565b6000808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612e79576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f556e697377617056324c6962726172793a204944454e544943414c5f4144445260448201527f455353455300000000000000000000000000000000000000000000000000000060648201526084016105c3565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610612eb3578284612eb6565b83835b909250905073ffffffffffffffffffffffffffffffffffffffff8216612f38576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f556e697377617056324c6962726172793a205a45524f5f41444452455353000060448201526064016105c3565b9250929050565b6000808411612fd0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4160448201527f4d4f554e5400000000000000000000000000000000000000000000000000000060648201526084016105c3565b600083118015612fe05750600082115b61306c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f556e697377617056324c6962726172793a20494e53554646494349454e545f4c60448201527f495155494449545900000000000000000000000000000000000000000000000060648201526084016105c3565b8261307783866143a0565b613081919061433c565b949350505050565b60065460609060009081908690869073ffffffffffffffffffffffffffffffffffffffff163314838a1561320a57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166338ed17398b858f308d6040518663ffffffff1660e01b815260040161311a9594939291906145b5565b6000604051808303816000875af1158015613139573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261317f9190810190614641565b965061271087600181518110613197576131976143b7565b602002602001015160036131ab91906143a0565b6131b5919061433c565b9550816131c35760006131f7565b612710876001815181106131d9576131d96143b7565b602002602001015160026131ed91906143a0565b6131f7919061433c565b945061320385876145a2565b905061330b565b6127106132188a60036143a0565b613222919061433c565b955081613230576000613248565b61271061323e8a60026143a0565b613248919061433c565b945061325485876145a2565b60035490915073ffffffffffffffffffffffffffffffffffffffff16638803dbee61327f838c6145a2565b868f308d6040518663ffffffff1660e01b81526004016132a39594939291906145b5565b6000604051808303816000875af11580156132c2573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526133089190810190614641565b96505b8b60008151811061331e5761331e6143b7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167fa082022e93cfcd9f1da5f9236718053910f7e840da080c789c7845698dc032ff89600081518110613387576133876143b7565b60200260200101518a6001815181106133a2576133a26143b7565b60200260200101516040516133c1929190918252602082015260400190565b60405180910390a380876001815181106133dd576133dd6143b7565b602002602001018181516133f19190614350565b915081815250505050505096509650969350505050565b60065460609060009081908690869073ffffffffffffffffffffffffffffffffffffffff163314838a1561353b576127106134448b60036143a0565b61344e919061433c565b95508161345c576000613474565b61271061346a8b60026143a0565b613474919061433c565b945061348085876145a2565b60035490915073ffffffffffffffffffffffffffffffffffffffff166338ed17396134ab838d614350565b858f308d6040518663ffffffff1660e01b81526004016134cf9594939291906145b5565b6000604051808303816000875af11580156134ee573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526135349190810190614641565b965061368a565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638803dbee8a868f308d6040518663ffffffff1660e01b815260040161359e9594939291906145b5565b6000604051808303816000875af11580156135bd573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526136039190810190614641565b96506127108760008151811061361b5761361b6143b7565b6020026020010151600361362f91906143a0565b613639919061433c565b95508161364757600061367b565b6127108760008151811061365d5761365d6143b7565b6020026020010151600261367191906143a0565b61367b919061433c565b945061368785876145a2565b90505b8b60018151811061369d5761369d6143b7565b602002602001015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f89f5adc174562e07c9c9b1cae7109bbecb21cf9d1b2847e550042b8653c54a0e89600081518110613706576137066143b7565b60200260200101518a600181518110613721576137216143b7565b6020026020010151604051613740929190918252602082015260400190565b60405180910390a3808760008151811061375c5761375c6143b7565b602002602001018181516133f191906145a2565b60085461379490839073ffffffffffffffffffffffffffffffffffffffff166113c2565b60808501526137a8640100000000426146d7565b63ffffffff1660a08501526060840151613855576005546040517fef57ff2d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301529091169063ef57ff2d90602401602060405180830381865afa15801561382c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138509190614363565b6138e9565b6005546040517f1959f77800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015290911690631959f77890602401602060405180830381865afa1580156138c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138e99190614363565b60c0850190815273ffffffffffffffffffffffffffffffffffffffff80851660008181526001602081815260408084209589168085529582528084208885528252928390208a51808255918b0151928101839055838b01516002820181905560608c01516003830180548215157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911617905560808d0151600484015560a08d015160058401805463ffffffff9092167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000090921691909117905597516006909201919091559251949593947fa0da177c50de7b9d2ef872a12ba0253ac6a13b8c2987a94198f6c09cebbe656694613a26948994929091909485526020850193909352604084019190915260608301521515608082015260a00190565b60405180910390a350505050565b6020870151600090613a478560646143a0565b613a51919061433c565b905060006064828a60000151613a6791906143a0565b613a71919061433c565b90506000613a7f84836146eb565b905060006064848c60400151613a9591906143a0565b613a9f919061433c565b9050828b600001818151613ab39190614350565b90525060208b018051889190613aca908390614350565b90525060408b018051829190613ae1908390614350565b90525060608b01518015613b0a57613af98288614713565b613b0390846146eb565b9250613b21565b613b148783614713565b613b1e90846146eb565b92505b60045473ffffffffffffffffffffffffffffffffffffffff16630363a1618c60008613613b5657613b518661456a565b613b58565b855b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152600086136044820152606401600060405180830381600087803b158015613bcc57600080fd5b505af1158015613be0573d6000803e3d6000fd5b5050604080518c8152602081018890529081018b9052606081018a9052831515608082015260a0810186905273ffffffffffffffffffffffffffffffffffffffff808e1693508e1691507f2129da0bc7433471df98bc9551d98bfda0f2c2eff005eeca7759217c73fa5aa99060c00160405180910390a3505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611d9f57600080fd5b600080600060608486031215613c9c57600080fd5b8335613ca781613c65565b92506020840135613cb781613c65565b929592945050506040919091013590565b8015158114611d9f57600080fd5b600080600080600080600060e0888a031215613cf157600080fd5b8735613cfc81613c65565b96506020880135613d0c81613cc8565b95506040880135613d1c81613cc8565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b600080600080600060a08688031215613d5c57600080fd5b8535613d6781613c65565b97602087013597506040870135966060810135965060800135945092505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613dfe57613dfe613d88565b604052919050565b600067ffffffffffffffff821115613e2057613e20613d88565b5060051b60200190565b600082601f830112613e3b57600080fd5b8135613e4e613e4982613e06565b613db7565b8082825260208201915060208360051b860101925085831115613e7057600080fd5b602085015b83811015613e96578035613e8881613c65565b835260209283019201613e75565b5095945050505050565b600082601f830112613eb157600080fd5b8135613ebf613e4982613e06565b8082825260208201915060208360051b860101925085831115613ee157600080fd5b602085015b83811015613e96578035835260209283019201613ee6565b600080600060608486031215613f1357600080fd5b833567ffffffffffffffff811115613f2a57600080fd5b613f3686828701613e2a565b935050602084013567ffffffffffffffff811115613f5357600080fd5b613f5f86828701613e2a565b925050604084013567ffffffffffffffff811115613f7c57600080fd5b613f8886828701613ea0565b9150509250925092565b600060208284031215613fa457600080fd5b8135613faf81613c65565b9392505050565b60008060008060008060c08789031215613fcf57600080fd5b8635613fda81613c65565b95506020870135613fea81613c65565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60008060006060848603121561402457600080fd5b833561402f81613c65565b95602085013595506040909401359392505050565b6000806040838503121561405757600080fd5b823561406281613c65565b9150602083013561407281613c65565b809150509250929050565b6000806000806080858703121561409357600080fd5b843567ffffffffffffffff8111156140aa57600080fd5b6140b687828801613e2a565b945050602085013567ffffffffffffffff8111156140d357600080fd5b6140df87828801613ea0565b935050604085013567ffffffffffffffff8111156140fc57600080fd5b8501601f8101871361410d57600080fd5b803561411b613e4982613e06565b8082825260208201915060208360051b85010192508983111561413d57600080fd5b6020840193505b8284101561415f578335825260209384019390910190614144565b9699959850959660600135955050505050565b60e08101612b3b82848051825260208101516020830152604081015160408301526060810151151560608301526080810151608083015263ffffffff60a08201511660a083015260c081015160c08301525050565b600080600080600080600080610100898b0312156141e457600080fd5b88356141ef81613c65565b975060208901356141ff81613c65565b9650604089013561420f81613cc8565b9550606089013561421f81613cc8565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b60006020828403121561425957600080fd5b8151613faf81613cc8565b835481526001840154602082015260028401546040820152600384015460ff161515606082015260048401546080820152600584015463ffffffff1660a0820152600684015460c082015273ffffffffffffffffffffffffffffffffffffffff83811660e083015282166101008201526101208101613081565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008261434b5761434b6142de565b500490565b81810381811115612b3b57612b3b61430d565b60006020828403121561437557600080fd5b5051919050565b6000806040838503121561438f57600080fd5b505080516020909101519092909150565b8082028115828204841417612b3b57612b3b61430d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000806000606084860312156143fb57600080fd5b5050815160208301516040909301519094929350919050565b80516dffffffffffffffffffffffffffff8116811461443257600080fd5b919050565b60008060006060848603121561444c57600080fd5b61445584614414565b925061446360208501614414565b9150604084015163ffffffff8116811461447c57600080fd5b809150509250925092565b6000825160005b818110156144a8576020818601810151858301520161448e565b506000920191825250919050565b6000602082840312156144c857600080fd5b8151613faf81613c65565b610120810161452982868051825260208101516020830152604081015160408301526060810151151560608301526080810151608083015263ffffffff60a08201511660a083015260c081015160c08301525050565b73ffffffffffffffffffffffffffffffffffffffff841660e083015273ffffffffffffffffffffffffffffffffffffffff8316610100830152949350505050565b60007f8000000000000000000000000000000000000000000000000000000000000000820361459b5761459b61430d565b5060000390565b80820180821115612b3b57612b3b61430d565b600060a0820187835286602084015260a0604084015280865180835260c08501915060208801925060005b8181101561461457835173ffffffffffffffffffffffffffffffffffffffff168352602093840193909201916001016145e0565b505073ffffffffffffffffffffffffffffffffffffffff9590951660608401525050608001529392505050565b60006020828403121561465357600080fd5b815167ffffffffffffffff81111561466a57600080fd5b8201601f8101841361467b57600080fd5b8051614689613e4982613e06565b8082825260208201915060208360051b8501019250868311156146ab57600080fd5b6020840193505b828410156146cd5783518252602093840193909101906146b2565b9695505050505050565b6000826146e6576146e66142de565b500690565b808201828112600083128015821682158216171561470b5761470b61430d565b505092915050565b81810360008312801583831316838312821617156147335761473361430d565b509291505056fea26469706673582212205a9c8b0ba66eef68deea99ce8b92a4a12900709811af8b780c8f90316adca54164736f6c634300081a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.