ETH Price: $3,502.64 (-0.19%)
Gas: 2 Gwei

Contract

0x4214eB7988c3E1bA12c9F146eBfF8d15ed7687DE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Process Orders198501812024-05-11 23:50:2370 days ago1715471423IN
0x4214eB79...5ed7687DE
0 ETH0.000091124.05612102
Process Orders196581472024-04-15 3:10:2397 days ago1713150623IN
0x4214eB79...5ed7687DE
0 ETH0.000203459.0563965
Process Orders192119072024-02-12 12:20:35159 days ago1707740435IN
0x4214eB79...5ed7687DE
0 ETH0.0004238218.86608592
Process Orders192082942024-02-12 0:11:11160 days ago1707696671IN
0x4214eB79...5ed7687DE
0 ETH0.0005838925.99151253
Process Orders192082452024-02-12 0:00:35160 days ago1707696035IN
0x4214eB79...5ed7687DE
0 ETH0.0005678425.27680819
Process Orders192081952024-02-11 23:50:35160 days ago1707695435IN
0x4214eB79...5ed7687DE
0 ETH0.0004559720.29712782
Process Orders192081452024-02-11 23:40:35160 days ago1707694835IN
0x4214eB79...5ed7687DE
0 ETH0.0004818521.44922918
Process Orders192080962024-02-11 23:30:35160 days ago1707694235IN
0x4214eB79...5ed7687DE
0 ETH0.0005432824.18382542
Process Orders192080472024-02-11 23:20:35160 days ago1707693635IN
0x4214eB79...5ed7687DE
0 ETH0.0006823830.37539481
Process Orders192079972024-02-11 23:10:35160 days ago1707693035IN
0x4214eB79...5ed7687DE
0 ETH0.0014734565.58882063
Process Orders192079472024-02-11 23:00:35160 days ago1707692435IN
0x4214eB79...5ed7687DE
0 ETH0.0006011226.7581272
Process Orders192078972024-02-11 22:50:35160 days ago1707691835IN
0x4214eB79...5ed7687DE
0 ETH0.0007256432.30135096
Process Orders192078472024-02-11 22:40:35160 days ago1707691235IN
0x4214eB79...5ed7687DE
0 ETH0.0007896435.15016458
Process Orders192077982024-02-11 22:30:47160 days ago1707690647IN
0x4214eB79...5ed7687DE
0 ETH0.0007896335.14935284
Process Orders192077472024-02-11 22:20:35160 days ago1707690035IN
0x4214eB79...5ed7687DE
0 ETH0.00465237207.09458735
Process Orders192076972024-02-11 22:10:35160 days ago1707689435IN
0x4214eB79...5ed7687DE
0 ETH0.0007481133.30135608
Process Orders192076472024-02-11 22:00:35160 days ago1707688835IN
0x4214eB79...5ed7687DE
0 ETH0.000626127.87008764
Process Orders192075972024-02-11 21:50:35160 days ago1707688235IN
0x4214eB79...5ed7687DE
0 ETH0.0005967326.56295481
Process Orders192075472024-02-11 21:40:35160 days ago1707687635IN
0x4214eB79...5ed7687DE
0 ETH0.0006574729.26668143
Process Orders192074982024-02-11 21:30:35160 days ago1707687035IN
0x4214eB79...5ed7687DE
0 ETH0.0008215436.56984569
Process Orders192074502024-02-11 21:20:35160 days ago1707686435IN
0x4214eB79...5ed7687DE
0 ETH0.0006149527.37372565
Process Orders192074002024-02-11 21:10:35160 days ago1707685835IN
0x4214eB79...5ed7687DE
0 ETH0.0006101727.16102134
Process Orders192073502024-02-11 21:00:35160 days ago1707685235IN
0x4214eB79...5ed7687DE
0 ETH0.0006507428.967014
Process Orders192073012024-02-11 20:50:35160 days ago1707684635IN
0x4214eB79...5ed7687DE
0 ETH0.0007488833.33554263
Process Orders192072542024-02-11 20:40:47160 days ago1707684047IN
0x4214eB79...5ed7687DE
0 ETH0.0006596229.36226189
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:
UrulokiDEX

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 3 : UrulokiDex.sol
// SPDX-License-Identifier: UNLICENSED
// Uruloki DEX is NOT LICENSED FOR COPYING.
// Uruloki DEX (C) 2022. All Rights Reserved.

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

interface IUniswapV2Router {
    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;

    function getAmountsOut(
        uint amountIn,
        address[] calldata path
    ) external view returns (uint[] memory amounts);
}

interface IUniswapV2Factory {
    function getPair(
        address tokenA, 
        address tokenB
    ) external view returns (address pair);
}

interface IOrderMgr {
    //// Define enums
    enum OrderType {
        TargetPrice,
        PriceRange
    }
    enum OrderStatus {
        Active,
        Cancelled,
        OutOfFunds,
        Completed
    }

    //// Define structs
    // One time order, it's a base order struct
    struct OrderBase {
        address userAddress;
        address pairedTokenAddress;
        address tokenAddress;
        OrderType orderType;
        uint256 targetPrice;
        bool isBuy;
        uint256 maxPrice;
        uint256 minPrice;
        OrderStatus status;
        uint256 amount;
        uint256 slippage;
        bool isContinuous;
    }

    // Continuous Order, it's an extended order struct, including the base order struct
    struct Order {
        OrderBase orderBase;
        uint256 numExecutions;
        uint256 resetPercentage;
        bool hasPriceReset;
    }

    function createOneTimeOrder(
        address userAddress,
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 targetPrice,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage
    ) external returns (uint256);

    function createContinuousOrder(
        address userAddress,
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 targetPrice,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage,
        uint256 resetPercentage
    ) external returns (uint256);

    function updateOrder(
        uint256 orderId,
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 targetPrice,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage,
        uint256 resetPercentage
    ) external;

    function cancelOrder(uint256 orderId) external returns (uint256);

    function orderCounter() external view returns (uint256);

    function getOrder(uint256 orderId) external view returns (Order memory);

    function setOrderStatus(
        uint256 orderId,
        IOrderMgr.OrderStatus status
    ) external;

    function incNumExecutions(uint256 orderId) external;

    function setHasPriceReset(uint256 orderId, bool flag) external;
}

interface IERC20Ext is IERC20 {
    function decimals() external view returns (uint8);
}

contract UrulokiDEX is ReentrancyGuard {
    //// Define events
    // Event emitted when a one-time order is created
    event OneTimeOrderCreated(uint256 orderId);

    // Event emitted when a continuous order is created
    event ContinuousOrderCreated(uint256 orderId);

    // Event emitted when a one-time order is edited
    event OneTimeOrderEdited(uint256 orderId);

    // Event emitted when a continuous order is edited
    event ContinuousOrderEdited(uint256 orderId);

    // Event emitted when an order is canceled
    event OrderCanceled(uint256 orderId);

    // Event emitted when the price is outside of the specified price range
    event ExecutedOutOfPrice(uint256 orderId, bool isBuy, uint256 price);

    // Event emitted when a one-time order is successfully executed
    event ExecutedOneTimeOrder(
        uint256 orderId,
        bool isBuy,
        uint256 pairAmount,
        uint256 tokenAmount,
        uint256 price
    );

    // Event emitted when a continuous order is successfully executed
    event ExecutedContinuousOrder(
        uint256 orderId,
        bool isBuy,
        uint256 price
    );

    // Event emitted when funds are withdrawn from a user's address
    event FundsWithdrawn(
        address userAddress,
        address tokenAddress,
        uint256 amount
    );

    // Event emitted when the owner of the contract is changed
    event BackendOwner(address newOwner);

    // Event emitted when an order is out of funds
    event OutOfFunds(uint256 orderId);

    // Event emitted when a swap during order execution fails
    event SwapFailed(uint256 orderId);

    // This event is emitted when no valid pairs for USDC, USDT, TSUKA, or WETH are found for the specified order
    event PairNotFound(uint256 orderId);

    //// Define constants
    address private constant UNISWAP_V2_ROUTER =
        0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    address private constant UNISWAP_V2_FACTORY =
        0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
    address private constant WETH =
        0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    address private constant USDT =
        0xc28ab4E347dd26C5809540e7dB0CEa473D91439c;
    address private constant USDC =
        0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address private constant TSUKA =
        0xc5fB36dd2fb59d3B98dEfF88425a3F425Ee469eD;

    //// Define variables
    mapping(address => mapping(address => uint256)) public balances;

    IUniswapV2Router private uniswapRouter =
        IUniswapV2Router(UNISWAP_V2_ROUTER);
    IUniswapV2Factory private uniswapFactory =
        IUniswapV2Factory(UNISWAP_V2_FACTORY);

    address public backend_owner;
    address public orderMgrAddress;
    IOrderMgr _orderMgr;

    constructor() {
        backend_owner = msg.sender;
    }

    modifier initOneTimeOrderBalance (
        uint256 orderId
    ) {
        IOrderMgr.Order memory order = _orderMgr.getOrder(orderId);

        // Validate order owner
        require(
            order.orderBase.userAddress == msg.sender,
            "msg.sender is not order owner"
        );

        // Check if the order is a one-time order
        require(order.orderBase.isContinuous == false, "Incorrect order type");

        // Check if the order status is active
        require(order.orderBase.status == IOrderMgr.OrderStatus.Active, "Incorrect order status");

        // Update the balances based on the order type
        if(!order.orderBase.isBuy) {
            balances[msg.sender][order.orderBase.tokenAddress] += order.orderBase.amount;
        } else {
            balances[msg.sender][order.orderBase.pairedTokenAddress] += order.orderBase.amount;
        }

        _;
    }

    /**
     * @dev Validates a one-time order by checking the user's balance and updating it if necessary
     * @param pairedTokenAddress The address of the paired token
     * @param tokenAddress The address of the token
     * @param isBuy Boolean indicating if it's a buy order
     * @param amount The amount of tokens in the order
     * @return bool Returns true if the order is valid, false otherwise
     */
    function validateOneTimeOrder(
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 amount
    ) internal returns (bool) {
        // if buying token, pair token is spendable else if sell, the token is spendable
        if (!isBuy) {
            // Check if the user has enough balance
            if(balances[msg.sender][tokenAddress] >= amount) {
                // Update the user's balance
                balances[msg.sender][tokenAddress] -= amount;
            } else 
                return false;
        } else {
            // Check if the user has enough balance
            if(balances[msg.sender][pairedTokenAddress] >= amount) {
                // Update the user's balance
                balances[msg.sender][pairedTokenAddress] -= amount;
            } else 
                return false;
        }

        return true;
    }

    // set backend owner address
    function setBackendOwner(address new_owner) public {
        require(msg.sender == backend_owner, "Not admin");
        backend_owner = new_owner;
        emit BackendOwner(backend_owner);
    }

    function setOrderMgr(address _orderMgrAddress) public {
        require(msg.sender == backend_owner, "setOrderMgr: not allowed");
        require(
            _orderMgrAddress != address(0),
            "setOrderMgr: invalid orderMgrAddress"
        );
        orderMgrAddress = _orderMgrAddress;
        _orderMgr = IOrderMgr(_orderMgrAddress);
    }

    /**
     * @notice allows users to make a deposit
     * @dev token should be transferred from the user wallet to the contract
     * @param tokenAddress token address
     * @param amount deposit amount
     */
    function addFunds(
        address tokenAddress,
        uint256 amount
    ) external nonReentrant {
        require(amount > 0, "Amount must be greater than zero");

        IERC20 token = IERC20(tokenAddress);
        uint256 balanceBefore = token.balanceOf(address(this));

        require(
            token.transferFrom(msg.sender, address(this), amount),
            "Transfer failed"
        );

        // Update the user's balance
        balances[USDT][tokenAddress] += token.balanceOf(address(this)) - balanceBefore;
        balances[msg.sender][tokenAddress] = balances[USDT][tokenAddress];
    }

    /**
     * @dev funds withdrawal external call
     * @param tokenAddress token address
     * @param amount token amount
     */
    function withdrawFunds(
        address tokenAddress,
        uint256 amount
    ) external nonReentrant {
        require(amount > 0, "Amount must be greater than zero");

        // Check if the user has enough balance to withdraw
        require(
            balances[msg.sender][tokenAddress] >= amount,
            "Insufficient balance"
        );

        // Update the user's balance
        balances[msg.sender][tokenAddress] -= amount;

        // Transfer ERC20 token to the user
        IERC20 token = IERC20(tokenAddress);
        require(token.transfer(msg.sender, amount), "Transfer failed");
        // Emit event
        emit FundsWithdrawn(msg.sender, tokenAddress, amount);
    }

    /**
     * @notice create non-continuous price range order
     * @dev The orders are only executed when the market price is less than or equal to the minPrice and greater than or equal to the maxPrice
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param minPrice Minimum price for the order. The value's decimal is in USDC decimal 6 format
     * @param maxPrice Maximum price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     */
    function createNonContinuousPriceRangeOrder(
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage
    )   external nonReentrant {
        require(validateOneTimeOrder(pairedTokenAddress, tokenAddress, isBuy, amount), "Validation failed");

        uint256 id = _orderMgr.createOneTimeOrder(
            msg.sender,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            0,
            minPrice,
            maxPrice,
            amount,
            slippage
        );
        // Emit an event
        emit OneTimeOrderCreated(id);
    }

    /**
     * @notice creates a non-continuous order with a target price
     * @dev Target price orders are only executed when certain conditions are met:
     * - For buy orders, the market price must be less than or equal to the target price
     * - For sell orders, the market price must be greater than or equal to the target price
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param targetPrice The target price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     */
    function createNonContinuousTargetPriceOrder(
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 targetPrice,
        uint256 amount,
        uint256 slippage
    )   external nonReentrant {
        require(validateOneTimeOrder(pairedTokenAddress, tokenAddress, isBuy, amount), "Validation failed");

        // Create a new order
        uint256 id = _orderMgr.createOneTimeOrder(
            msg.sender,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            targetPrice,
            0,
            0,
            amount,
            slippage
        );

        // Emit event
        emit OneTimeOrderCreated(id);
    }

    /**
     * @notice creates a continuous order with price range
     * @dev The orders are only executed continuely when the market price is less than or equal to the minPrice and greater than or equal to the maxPrice
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param minPrice Minimum price for the order. The value's decimal is in USDC decimal 6 format
     * @param maxPrice Maximum price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     * @param resetPercentage decimal represented as an int with 0 places of precision
     */
    function createContinuousPriceRangeOrder(
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage,
        uint256 resetPercentage
    ) external nonReentrant {
        uint256 id = _orderMgr.createContinuousOrder(
            msg.sender,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            0,
            minPrice,
            maxPrice,
            amount,
            slippage,
            resetPercentage
        );

        // Emit an event
        emit ContinuousOrderCreated(id);
    }

    /**
     * @notice creates a continuous order with a target price
     * @dev The orders are only executed continuely when certain conditions are met:
     * - For buy orders, the market price must be less than or equal to the target price
     * - For sell orders, the market price must be greater than or equal to the target price
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param targetPrice The target price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     * @param resetPercentage decimal represented as an int with 0 places of precision
     */
    function createContinuousTargetPriceOrder(
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 targetPrice,
        uint256 amount,
        uint256 slippage,
        uint256 resetPercentage
    ) external nonReentrant {
        // Create the ContinuousOrder struct
        uint256 id = _orderMgr.createContinuousOrder(
            msg.sender,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            targetPrice,
            0,
            0,
            amount,
            slippage,
            resetPercentage
        );

        // Emit an event
        emit ContinuousOrderCreated(id);
    }

    /**
     * @dev cancel exist order
     * @param orderId order id
     */
    function cancelOrder(uint256 orderId) external {
        // Validate order owner
        IOrderMgr.Order memory order = _orderMgr.getOrder(orderId);
        require(
            order.orderBase.userAddress == msg.sender,
            "msg.sender is not order owner"
        );

        _orderMgr.cancelOrder(orderId);
        if (!order.orderBase.isContinuous)
            if (order.orderBase.isBuy) {
                balances[msg.sender][order.orderBase.pairedTokenAddress] += order
                    .orderBase
                    .amount;
            } else {
                balances[msg.sender][order.orderBase.tokenAddress] += order
                    .orderBase
                    .amount;
            }

        // Emit event
        emit OrderCanceled(orderId);
    }

    /**
     * @notice process a one-time order
     * @dev internal function
     * @param orderId id of the order
     */
    function _processOneTimeOrder(IOrderMgr.Order memory order, uint256 orderId) internal returns (bool) {
        // Get the price in amount
        uint256 price = _getPairPrice(
            order.orderBase.tokenAddress,
            10 ** IERC20Ext(order.orderBase.tokenAddress).decimals()
        );
        
        if(price == 0) {
            emit PairNotFound(orderId);
            return false;
        }

        address fromToken;
        address toToken;
        uint256 toAmount;
        bool swapStatus;

        // Check if the order type is PriceRange
        if (order.orderBase.orderType == IOrderMgr.OrderType.PriceRange) {
            if (
                order.orderBase.minPrice > price || price > order.orderBase.maxPrice
            ) {
                emit ExecutedOutOfPrice(orderId, order.orderBase.isBuy, price);
                return false;
            }
        }

        if (order.orderBase.isBuy) {
            // Check if the order type is TargetPrice
            if (order.orderBase.orderType == IOrderMgr.OrderType.TargetPrice) {
                if (
                    price > order.orderBase.targetPrice
                ) {
                    emit ExecutedOutOfPrice(orderId, order.orderBase.isBuy, price);
                    return false;
                }
            }
            fromToken = order.orderBase.pairedTokenAddress;
            toToken = order.orderBase.tokenAddress;
        } else {
            // Check if the order type is TargetPrice
            if (order.orderBase.orderType == IOrderMgr.OrderType.TargetPrice) {
                if (price < order.orderBase.targetPrice) {
                    emit ExecutedOutOfPrice(orderId, order.orderBase.isBuy, price);
                    return false;
                }
            }
            fromToken = order.orderBase.tokenAddress;
            toToken = order.orderBase.pairedTokenAddress;
        }

        (toAmount, swapStatus) = _swapTokens(
            fromToken, 
            toToken, 
            order.orderBase.amount,
            order.orderBase.slippage
        );

        if(swapStatus) {
            balances[order.orderBase.userAddress][toToken] += toAmount;

            _orderMgr.setOrderStatus(orderId, IOrderMgr.OrderStatus.Completed);
            emit ExecutedOneTimeOrder(
                orderId,
                order.orderBase.isBuy,
                order.orderBase.amount,
                toAmount,
                price
            );

            return true;
        } else {
            emit SwapFailed(orderId);
            return false;
        }
    }

    /**
     * @notice process a continuous order
     * @dev internal function
     * @param orderId id of the order
     */
    function _processContinuousOrder(IOrderMgr.Order memory order, uint256 orderId) internal returns (bool){
        if (order.orderBase.targetPrice == 0) {
            // Price range order
            return _processContinuousPriceRangeOrder(order, orderId);
        } else {
            // Target price order
            return _processContinuousTargetPriceOrder(order, orderId);
        }
    }

    /**
     * @dev Internal function to process a continuous price range order
     * @param order The order memory instance
     * @param orderId Order ID
     * @return bool Returns true if the order is processed successfully, false otherwise
     */
    function _processContinuousPriceRangeOrder(
        IOrderMgr.Order memory order,
        uint256 orderId
    ) internal returns(bool) {
        // Get the price in amount
        uint256 price = _getPairPrice(
            order.orderBase.tokenAddress,
            10 ** IERC20Ext(order.orderBase.tokenAddress).decimals()
        );

        // Check if the price is not found for the pair
        if(price == 0) {
            emit PairNotFound(orderId);
            return false;
        }

        // Check if the order has price reset
        if (order.hasPriceReset) {
            // Check if the price is within the specified range
            if (
                !(
                price > order.orderBase.minPrice 
                && price < order.orderBase.maxPrice
                )
            ) {
                emit ExecutedOutOfPrice(orderId, order.orderBase.isBuy, price);
                return false;
            }
            address fromToken;
            address toToken;
            uint256 toAmount;
            bool swapStatus;

            // Determine the tokens for swapping based on the order type
            if (order.orderBase.isBuy) {
                fromToken = order.orderBase.pairedTokenAddress;
                toToken = order.orderBase.tokenAddress;
            } else {
                fromToken = order.orderBase.tokenAddress;
                toToken = order.orderBase.pairedTokenAddress;
            }

            // Check if the user has enough balance of the fromToken
            if (
                balances[order.orderBase.userAddress][fromToken] >=
                order.orderBase.amount
            ) {
                // Swap tokens
                (toAmount, swapStatus) = _swapTokens(
                    fromToken,
                    toToken,
                    order.orderBase.amount,
                    order.orderBase.slippage
                );

                if(swapStatus) {
                    // Update user's balances
                    balances[order.orderBase.userAddress][toToken] += toAmount;
                    balances[order.orderBase.userAddress][fromToken] -= order
                        .orderBase
                        .amount;
                    
                    // Update order status and execution count
                    _orderMgr.setOrderStatus(orderId, IOrderMgr.OrderStatus.Active);
                    _orderMgr.incNumExecutions(orderId);
                    _orderMgr.setHasPriceReset(orderId, false);

                    emit ExecutedContinuousOrder(orderId, order.orderBase.isBuy, price);
                } else {
                    emit SwapFailed(orderId);
                }
            } else {
                // Set order status as out of funds
                _orderMgr.setOrderStatus(
                    orderId,
                    IOrderMgr.OrderStatus.OutOfFunds
                );
                emit OutOfFunds(orderId);
            }
        } else {
            // Calculate the lower and upper price differences based on the reset percentage
            uint256 lowerDiff = (order.orderBase.minPrice *
                order.resetPercentage) / 100;
            uint256 upperDiff = (order.orderBase.maxPrice *
                order.resetPercentage) / 100;

            // Check if the price is outside the adjusted range
            if (
                !(price < order.orderBase.minPrice - lowerDiff
                || price > order.orderBase.maxPrice + upperDiff)
            ) {
                return false;
            }

            // Set hasPriceReset to true for the order
            _orderMgr.setHasPriceReset(orderId, true);
        }
        
        return true;
    }

    /**
     * @dev Processes a continuous order with a target price
     * @param order The order to process
     * @param orderId The ID of the order
     * @return bool Returns true if the order is successfully processed, false otherwise
     */
    function _processContinuousTargetPriceOrder(
        IOrderMgr.Order memory order,
        uint256 orderId
    ) internal returns (bool) {
        // Get the price in amount
        uint256 price = _getPairPrice(
            order.orderBase.tokenAddress,
            10 ** IERC20Ext(order.orderBase.tokenAddress).decimals()
        );

        // Check if the price is 0, indicating that the pair does not exist
        if(price == 0) {
            emit PairNotFound(orderId);
            return false;
        }

        // Check if the order is a buy order
        if (order.orderBase.isBuy) {
            // Check if the order has price reset
            if (order.hasPriceReset) {
                // Check if the current price is greater than the target price
                if (price > order.orderBase.targetPrice) {
                    emit ExecutedOutOfPrice(orderId, order.orderBase.isBuy, price);
                    return false;
                }

                // Swap tokens and update balances
                address fromToken;
                address toToken;
                uint256 toAmount;
                bool swapStatus;

                fromToken = order.orderBase.pairedTokenAddress;
                toToken = order.orderBase.tokenAddress;

                // Check if the user has sufficient balance of fromToken
                if (
                    balances[order.orderBase.userAddress][fromToken] >=
                    order.orderBase.amount
                ) {
                    (toAmount, swapStatus) = _swapTokens(
                        fromToken,
                        toToken,
                        order.orderBase.amount,
                        order.orderBase.slippage
                    );

                    if(swapStatus) {
                        // Update user's balances
                        balances[order.orderBase.userAddress][toToken] += toAmount;
                        balances[order.orderBase.userAddress][fromToken] -= order
                            .orderBase
                            .amount;

                        // Update order status and execution count
                        _orderMgr.setOrderStatus(
                            orderId,
                            IOrderMgr.OrderStatus.Active
                        );
                        _orderMgr.incNumExecutions(orderId);
                        _orderMgr.setHasPriceReset(orderId, false);

                        emit ExecutedContinuousOrder(orderId, order.orderBase.isBuy, price);
                    } else {
                        emit SwapFailed(orderId);
                    }
                } else {
                    // Set order status as out of funds
                    _orderMgr.setOrderStatus(
                        orderId,
                        IOrderMgr.OrderStatus.OutOfFunds
                    );
                    emit OutOfFunds(orderId);
                }
            } else {
                uint256 diff = (order.orderBase.targetPrice *
                    order.resetPercentage) / 100;

                // Check if the current price is less than the target price plus the difference
                if (price < order.orderBase.targetPrice + diff) {
                    return false;
                }
                _orderMgr.setHasPriceReset(orderId, true);
            }
        } else {
            // Check if the order has price reset
            if (order.hasPriceReset) {
                // Check if the current price is less than the target price
                if (price < order.orderBase.targetPrice) {
                    emit ExecutedOutOfPrice(orderId, order.orderBase.isBuy, price);
                    return false;
                }

                // Swap tokens and update balances
                address fromToken;
                address toToken;
                uint256 toAmount;
                bool swapStatus;

                fromToken = order.orderBase.tokenAddress;
                toToken = order.orderBase.pairedTokenAddress;

                // Check if the user has sufficient balance of fromToken
                if (
                    balances[order.orderBase.userAddress][fromToken] >=
                    order.orderBase.amount
                ) {
                    (toAmount, swapStatus) = _swapTokens(
                        fromToken,
                        toToken,
                        order.orderBase.amount,
                        order.orderBase.slippage
                    );

                    if(swapStatus) {
                        balances[order.orderBase.userAddress][toToken] += toAmount;
                        balances[order.orderBase.userAddress][fromToken] -= order
                            .orderBase
                            .amount;

                        _orderMgr.setOrderStatus(
                            orderId,
                            IOrderMgr.OrderStatus.Active
                        );
                        _orderMgr.incNumExecutions(orderId);
                        _orderMgr.setHasPriceReset(orderId, false);

                        emit ExecutedContinuousOrder(orderId, order.orderBase.isBuy, price);
                    } else {
                        emit SwapFailed(orderId);
                    }
                } else {
                    _orderMgr.setOrderStatus(
                        orderId,
                        IOrderMgr.OrderStatus.OutOfFunds
                    );
                    emit OutOfFunds(orderId);
                }
            } else {
                uint256 diff = (order.orderBase.targetPrice *
                    order.resetPercentage) / 100;

                // Check if the current price is greater than the target price minus the difference
                if (price > order.orderBase.targetPrice - diff) {
                    return false;
                }
                _orderMgr.setHasPriceReset(orderId, true);
            }
        }
        
        return true;
    }

    /**
     * @dev Processes multiple orders based on the provided order IDs
     * @param orderIds An array of order IDs to process
     */
    function processOrders(
        uint256[] memory orderIds
    ) external {
        IOrderMgr.Order memory order;

        // Iterate through each order ID in the orderIds array
        for (uint256 i = 0; i < orderIds.length; i++) {
            order = _orderMgr.getOrder(orderIds[i]);
            uint256 orderId = orderIds[i];
            
            // Check if the tokenAddress of the order is the zero address
            // If it is, skip to the next iteration of the loop
            if (order.orderBase.tokenAddress == address(0))
                continue;

            // Check if the order is a continuous order
            if (order.orderBase.isContinuous == true) {
                // If the order is cancelled, skip to the next iteration of the loop
                if (order.orderBase.status == IOrderMgr.OrderStatus.Cancelled)
                    continue;
                _processContinuousOrder(order, orderId);
            } else {
                // If the order is not active, skip to the next iteration of the loop
                if (order.orderBase.status != IOrderMgr.OrderStatus.Active)
                    continue;
                _processOneTimeOrder(order, orderId);
            }
        }
    }

    /**
     * @dev Swaps tokens from one token to another using the Uniswap router
     * @param _fromTokenAddress The address of the token to swap from
     * @param _toTokenAddress The address of the token to swap to
     * @param _amount The amount of tokens to swap
     * @param _slippage The maximum acceptable slippage for the swap
     * @return uint256 The amount of tokens received after the swap
     * @return bool The status of the swap (true if successful, false otherwise)
     */
    function _swapTokens(
        address _fromTokenAddress,
        address _toTokenAddress,
        uint256 _amount,
        uint256 _slippage
    ) internal returns (uint256, bool) {
        IERC20 fromToken = IERC20(_fromTokenAddress);
        
        fromToken.approve(address(uniswapRouter), _amount);

        address[] memory path = new address[](2);
        path[0] = _fromTokenAddress;
        path[1] = _toTokenAddress;

        uint256 balanceBefore = IERC20(_toTokenAddress).balanceOf(address(this));
        
        try uniswapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
            _amount,
            _slippage,
            path,
            address(this),
            block.timestamp
        ) {} catch (bytes memory) {
            return (0, false);
        }
        uint256 toAmount = IERC20(_toTokenAddress).balanceOf(address(this)) - balanceBefore;

        // Return the amount of tokens received and the status of the swap
        return (toAmount, true);
    }

    /**
    * @dev Checks if a pair exists for the given tokens in the Uniswap exchange
    * @param token1 The address of the first token
    * @param token2 The address of the second token
    * @return bool Returns true if a pair exists, false otherwise
    */
    function checkIfPairExists(
        address token1,
        address token2
    ) public view returns(bool) {
        // Get the pair address from the Uniswap factory contract
        address pair = uniswapFactory.getPair(token1, token2);
        
        // If the pair address is equal to the zero address, it means the pair does not exist.
        if(pair == address(0)) return false;
        else return true;
    }

    /**
    * @dev Retrieves the price of a token pair based on the specified token address and amount
    * @param _tokenAddress The address of the token
    * @param _amount The amount of the token
    * @return uint256 The price of the token pair
    */
    function _getPairPrice(
        address _tokenAddress,
        uint256 _amount
    ) internal view returns (uint256) {
        // Check if a pair exists for USDC and the specified token
        if (checkIfPairExists(USDC, _tokenAddress)) {
            address[] memory path = new address[](2);
            path[0] = _tokenAddress;
            path[1] = USDC;
            return getAmountOut(path, _amount);
        }
        
        // Check if a pair exists for USDT and the specified token
        if (checkIfPairExists(USDT, _tokenAddress)) {
            address[] memory path = new address[](2);
            path[0] = _tokenAddress;
            path[1] = USDT;
            return getAmountOut(path, _amount);
        }
        
        // Check if a pair exists for WETH and the specified token
        if (checkIfPairExists(WETH, _tokenAddress)) {
            address[] memory path = new address[](3);
            path[0] = _tokenAddress;
            path[1] = WETH;
            path[2] = USDC;
            return getAmountOut(path, _amount);
        }
        
        // Check if a pair exists for TSUKA and the specified token
        if (checkIfPairExists(TSUKA, _tokenAddress)) {
            address[] memory path = new address[](3);
            path[0] = _tokenAddress;
            path[1] = TSUKA;
            path[2] = USDC;
            return getAmountOut(path, _amount);
        }
        
        // If no pair exists, return 0
        return 0;
    }

    /**
     * @dev Retrieves the amount out for a given input amount and path of token addresses
     * @param path The array of token addresses representing the path
     * @param amount The input amount
     * @return uint256 The amount out
     */
    function getAmountOut(
        address[] memory path,
        uint256 amount
    ) internal view returns (uint256) {
        // Get the amounts out for the specified input amount and path
        uint[] memory amountsOut = uniswapRouter.getAmountsOut(amount, path);
        
        // The getAmountsOut function from the Uniswap router contract is called with the specified input amount and path
        // It returns an array of amounts representing the output amounts at each step of the path

        // Return the amount out of the final token.
        // The amount out is obtained by accessing the last element of the amountsOut array using path.length - 1
        // This represents the output amount of the final token in the path after the swap
        return amountsOut[path.length - 1];
    }

    /**
     * @dev Retrieves the price of a token based on the specified token address
     * @param _tokenAddress The address of the token
     * @return uint256 The price of the token
     */
    function getTokenPrice(
        address _tokenAddress
    ) external view returns (uint256) {
        // Get the decimals of the token
        uint256 tokenDecimals = 10 ** IERC20Ext(_tokenAddress).decimals();

        // Get the pair price for the specified token
        return _getPairPrice(_tokenAddress, tokenDecimals);
    }

    /**
     * @notice edit a continuous order with target price
     * @param orderId Order id
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param targetPrice The target price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     * @param resetPercentage decimal represented as an int with 0 places of precision
     */
    function editContinuousTargetPriceOrder(
        uint256 orderId,
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 targetPrice,
        uint256 amount,
        uint256 slippage,
        uint256 resetPercentage
    ) external {
        IOrderMgr.Order memory order = _orderMgr.getOrder(orderId);
        // Validate order owner
        require(
            order.orderBase.userAddress == msg.sender,
            "msg.sender is not order owner"
        );
        // Is continous order
        require(order.orderBase.isContinuous == true, "Incorrect order type");

        _orderMgr.updateOrder(
            orderId,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            targetPrice,
            0,
            0,
            amount,
            slippage,
            resetPercentage
        );

        // Emit an event
        emit ContinuousOrderEdited(orderId);
    }

    /**
     * @notice edit a continuous order with price range
     * @param orderId order id
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param minPrice Minimum price for the order. The value's decimal is in USDC decimal 6 format
     * @param maxPrice Maximum price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     * @param resetPercentage decimal represented as an int with 0 places of precision
     */
    function editContinuousPriceRangeOrder(
        uint256 orderId,
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage,
        uint256 resetPercentage
    ) external {
        IOrderMgr.Order memory order = _orderMgr.getOrder(orderId);
        // Validate order owner
        require(
            order.orderBase.userAddress == msg.sender,
            "msg.sender is not order owner"
        );
        // Is continous order
        require(order.orderBase.isContinuous == true, "Incorrect order type");

        _orderMgr.updateOrder(
            orderId,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            0,
            minPrice,
            maxPrice,
            amount,
            slippage,
            resetPercentage
        );

        // Emit an event
        emit ContinuousOrderEdited(orderId);
    }

    /**
     * @notice Edit non-continuous order with price range
     * @param orderId Order id
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param minPrice Minimum price for the order. The value's decimal is in USDC decimal 6 format
     * @param maxPrice Maximum price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     */
    function editNonContinuousPriceRangeOrder(
        uint256 orderId,
        address pairedTokenAddress,
        address tokenAddress,
        bool isBuy,
        uint256 minPrice,
        uint256 maxPrice,
        uint256 amount,
        uint256 slippage
    ) 
        external
        nonReentrant
        initOneTimeOrderBalance(orderId)
    {
        require(validateOneTimeOrder(pairedTokenAddress, tokenAddress, isBuy, amount), "Validation failed");

        _orderMgr.updateOrder(
            orderId,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            0,
            minPrice,
            maxPrice,
            amount,
            slippage,
            0
        );
        // Emit an event
        emit OneTimeOrderEdited(orderId);
    }

    /**
     * @notice Edit a non-continuous order with a target price
     * @dev Target price order is only executed when the market price is equal to the target price
     * @param orderId Order id
     * @param pairedTokenAddress The address of the paired token in the trading pair
     * @param tokenAddress The address of the token being traded
     * @param isBuy Indicates whether it is a buy or sell order (true for buy, false for sell)
     * @param targetPrice The target price for the order. The value's decimal is in USDC decimal 6 format
     * @param amount The amount of tokens for the order. The value's decimal is the traded token decimal format.
     * @param slippage The slippage tolerance for the order. This is minAmountOut value and decimal is the traded token decimal format.
     */
    function editNonContinuousTargetPriceOrder(
        uint256 orderId,
        address pairedTokenAddress,
        address tokenAddress,
        uint256 targetPrice,
        bool isBuy,
        uint256 amount,
        uint256 slippage
    ) 
        external
        nonReentrant
        initOneTimeOrderBalance(orderId)
    {
        require(validateOneTimeOrder(pairedTokenAddress, tokenAddress, isBuy, amount), "Validation failed");

        _orderMgr.updateOrder(
            orderId,
            pairedTokenAddress,
            tokenAddress,
            isBuy,
            targetPrice,
            0,
            0,
            amount,
            slippage,
            0
        );

        // Emit event
        emit OneTimeOrderEdited(orderId);
    }
}

File 2 of 3 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

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

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

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

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

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

File 3 of 3 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"BackendOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"ContinuousOrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"ContinuousOrderEdited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"ExecutedContinuousOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":false,"internalType":"uint256","name":"pairAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"ExecutedOneTimeOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isBuy","type":"bool"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"ExecutedOutOfPrice","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FundsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OneTimeOrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OneTimeOrderEdited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OrderCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"OutOfFunds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"PairNotFound","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"SwapFailed","type":"event"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"addFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"backend_owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"}],"name":"cancelOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token1","type":"address"},{"internalType":"address","name":"token2","type":"address"}],"name":"checkIfPairExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"uint256","name":"resetPercentage","type":"uint256"}],"name":"createContinuousPriceRangeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"targetPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"uint256","name":"resetPercentage","type":"uint256"}],"name":"createContinuousTargetPriceOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"createNonContinuousPriceRangeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"targetPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"createNonContinuousTargetPriceOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"uint256","name":"resetPercentage","type":"uint256"}],"name":"editContinuousPriceRangeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"targetPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"},{"internalType":"uint256","name":"resetPercentage","type":"uint256"}],"name":"editContinuousTargetPriceOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"uint256","name":"maxPrice","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"editNonContinuousPriceRangeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"orderId","type":"uint256"},{"internalType":"address","name":"pairedTokenAddress","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"targetPrice","type":"uint256"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"editNonContinuousTargetPriceOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"getTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"orderMgrAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"orderIds","type":"uint256[]"}],"name":"processOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"new_owner","type":"address"}],"name":"setBackendOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_orderMgrAddress","type":"address"}],"name":"setOrderMgr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600280546001600160a01b0319908116737a250d5630b4cf539739df2c5dacb4c659f2488d1790915560038054909116735c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f179055348015610057575f80fd5b5060015f55600480546001600160a01b031916331790556137e78061007b5f395ff3fe608060405234801561000f575f80fd5b506004361061011c575f3560e01c8063514fcac7116100a9578063bc4b33651161006e578063bc4b336514610259578063c10753291461026c578063c23f001f1461027f578063d02641a0146102b7578063f77d4631146102ca575f80fd5b8063514fcac7146101fa5780635d58b7561461020d578063754dea40146102205780637720f717146102335780638bd4185814610246575f80fd5b806338800428116100ef578063388004281461016e5780633d1246d01461019e57806341929f0f146101c1578063441106c9146101d4578063452c4875146101e7575f80fd5b80630848a3c7146101205780630d48317b14610135578063209f90c3146101485780632b0b06621461015b575b5f80fd5b61013361012e366004612d19565b6102dd565b005b610133610143366004612d7a565b6103e3565b610133610156366004612df5565b610558565b610133610169366004612e67565b6107fa565b600554610181906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b16101ac366004612e82565b6108e2565b6040519015158152602001610195565b6101336101cf366004612f6e565b61097e565b6101336101e2366004612fff565b610aea565b6101336101f536600461306b565b610d8b565b6101336102083660046130d4565b610e5a565b61013361021b3660046130eb565b611038565b61013361022e366004612e67565b611107565b61013361024136600461306b565b6111a1565b610133610254366004612df5565b611284565b61013361026736600461315d565b6113f8565b61013361027a36600461315d565b611685565b6102a961028d366004612e82565b600160209081525f928352604080842090915290825290205481565b604051908152602001610195565b6102a96102c5366004612e67565b61187d565b600454610181906001600160a01b031681565b6102e56118fd565b6102f186868685611954565b6103165760405162461bcd60e51b815260040161030d90613187565b60405180910390fd5b600654604051630d570f1560e31b81525f916001600160a01b031690636ab878a8906103569033908b908b908b908b90899081908d908d906004016131b2565b6020604051808303815f875af1158015610372573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103969190613202565b90507f7ae91fe4742a77fb791e82e77c1b02800bd8fc0829aab88c2f0c1f5009a8d765816040516103c991815260200190565b60405180910390a1506103db60015f55565b505050505050565b60065460405163d09ef24160e01b8152600481018b90525f916001600160a01b03169063d09ef241906024016101e060405180830381865afa15801561042b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061044f9190613250565b8051519091506001600160a01b0316331461047c5760405162461bcd60e51b815260040161030d9061335a565b8051610160015115156001146104a45760405162461bcd60e51b815260040161030d90613391565b600654604051635585b19360e01b81526001600160a01b0390911690635585b193906104e6908d908d908d908d905f908e908e908e908e908e906004016133bf565b5f604051808303815f87803b1580156104fd575f80fd5b505af115801561050f573d5f803e3d5ffd5b505050507ff6889aa0780be70c770f893999b0adcc2cd01470d2ee0b90f706c5077d93e56b8a60405161054491815260200190565b60405180910390a150505050505050505050565b6105606118fd565b60065460405163d09ef24160e01b8152600481018a905289915f916001600160a01b039091169063d09ef241906024016101e060405180830381865afa1580156105ac573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d09190613250565b8051519091506001600160a01b031633146105fd5760405162461bcd60e51b815260040161030d9061335a565b80516101600151156106215760405162461bcd60e51b815260040161030d90613391565b5f81516101000151600381111561063a5761063a613410565b146106805760405162461bcd60e51b8152602060048201526016602482015275496e636f7272656374206f726465722073746174757360501b604482015260640161030d565b805160a001516106d25780516101200151335f90815260016020908152604080832085518201516001600160a01b03168452909152812080549091906106c7908490613438565b909155506107159050565b80516101200151335f90815260016020908152604080832085518301516001600160a01b031684529091528120805490919061070f908490613438565b90915550505b61072189898987611954565b61073d5760405162461bcd60e51b815260040161030d90613187565b600654604051635585b19360e01b81526001600160a01b0390911690635585b1939061077f908d908d908d908d905f908e908e908e908e9085906004016133bf565b5f604051808303815f87803b158015610796575f80fd5b505af11580156107a8573d5f803e3d5ffd5b505050507ff7f893fb8cda745632d6c27ec518a84338faeb6dbc795efb4cd00d29638610b38a6040516107dd91815260200190565b60405180910390a150506107f060015f55565b5050505050505050565b6004546001600160a01b031633146108545760405162461bcd60e51b815260206004820152601860248201527f7365744f726465724d67723a206e6f7420616c6c6f7765640000000000000000604482015260640161030d565b6001600160a01b0381166108b65760405162461bcd60e51b8152602060048201526024808201527f7365744f726465724d67723a20696e76616c6964206f726465724d67724164646044820152637265737360e01b606482015260840161030d565b600580546001600160a01b039092166001600160a01b0319928316811790915560068054909216179055565b60035460405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301525f92839291169063e6a4390590604401602060405180830381865afa158015610935573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610959919061344b565b90506001600160a01b038116610972575f915050610978565b60019150505b92915050565b610986612c7d565b5f5b8251811015610ae55760065483516001600160a01b039091169063d09ef241908590849081106109ba576109ba613466565b60200260200101516040518263ffffffff1660e01b81526004016109e091815260200190565b6101e060405180830381865afa1580156109fc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a209190613250565b91505f838281518110610a3557610a35613466565b60209081029190910101518351604001519091506001600160a01b0316610a5c5750610ad3565b825161016001511515600103610aa1576001835161010001516003811115610a8657610a86613410565b03610a915750610ad3565b610a9b8382611a2e565b50610ad1565b5f835161010001516003811115610aba57610aba613410565b14610ac55750610ad3565b610acf8382611a57565b505b505b80610add8161347a565b915050610988565b505050565b610af26118fd565b60065460405163d09ef24160e01b81526004810189905288915f916001600160a01b039091169063d09ef241906024016101e060405180830381865afa158015610b3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b629190613250565b8051519091506001600160a01b03163314610b8f5760405162461bcd60e51b815260040161030d9061335a565b8051610160015115610bb35760405162461bcd60e51b815260040161030d90613391565b5f815161010001516003811115610bcc57610bcc613410565b14610c125760405162461bcd60e51b8152602060048201526016602482015275496e636f7272656374206f726465722073746174757360501b604482015260640161030d565b805160a00151610c645780516101200151335f90815260016020908152604080832085518201516001600160a01b0316845290915281208054909190610c59908490613438565b90915550610ca79050565b80516101200151335f90815260016020908152604080832085518301516001600160a01b0316845290915281208054909190610ca1908490613438565b90915550505b610cb388888787611954565b610ccf5760405162461bcd60e51b815260040161030d90613187565b600654604051635585b19360e01b81526001600160a01b0390911690635585b19390610d11908c908c908c908b908d905f9081908e908e9083906004016133bf565b5f604051808303815f87803b158015610d28575f80fd5b505af1158015610d3a573d5f803e3d5ffd5b505050507ff7f893fb8cda745632d6c27ec518a84338faeb6dbc795efb4cd00d29638610b389604051610d6f91815260200190565b60405180910390a15050610d8260015f55565b50505050505050565b610d936118fd565b60065460405163d6f35bd560e01b81525f916001600160a01b03169063d6f35bd590610dd59033908c908c908c908c90899081908e908e908e90600401613492565b6020604051808303815f875af1158015610df1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e159190613202565b90507ff40951d004ae9ba03a1b52a13452626d3bbb2cd7a662dab67f84e8b564a9a06781604051610e4891815260200190565b60405180910390a150610d8260015f55565b60065460405163d09ef24160e01b8152600481018390525f916001600160a01b03169063d09ef241906024016101e060405180830381865afa158015610ea2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ec69190613250565b8051519091506001600160a01b03163314610ef35760405162461bcd60e51b815260040161030d9061335a565b60065460405163514fcac760e01b8152600481018490526001600160a01b039091169063514fcac7906024016020604051808303815f875af1158015610f3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5f9190613202565b508051610160015161100157805160a0015115610fbe5780516101200151335f90815260016020908152604080832085518301516001600160a01b0316845290915281208054909190610fb3908490613438565b909155506110019050565b80516101200151335f90815260016020908152604080832085518201516001600160a01b0316845290915281208054909190610ffb908490613438565b90915550505b6040518281527fc41f4ceb2938876c35e61b705e9d2f18a02c4a26ce5e049a6308a943d46851b39060200160405180910390a15050565b6110406118fd565b60065460405163d6f35bd560e01b81525f916001600160a01b03169063d6f35bd5906110829033908d908d908d9088908e908e908e908e908e90600401613492565b6020604051808303815f875af115801561109e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110c29190613202565b90507ff40951d004ae9ba03a1b52a13452626d3bbb2cd7a662dab67f84e8b564a9a067816040516110f591815260200190565b60405180910390a1506107f060015f55565b6004546001600160a01b0316331461114d5760405162461bcd60e51b81526020600482015260096024820152682737ba1030b236b4b760b91b604482015260640161030d565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f57a2989fbcdc251cf10758ea804ebbbd61e9da58a859d3fbf6bcfdd9c31bec7e9060200160405180910390a150565b6111a96118fd565b6111b587878785611954565b6111d15760405162461bcd60e51b815260040161030d90613187565b600654604051630d570f1560e31b81525f916001600160a01b031690636ab878a8906112119033908c908c908c9088908d908d908d908d906004016131b2565b6020604051808303815f875af115801561122d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112519190613202565b90507f7ae91fe4742a77fb791e82e77c1b02800bd8fc0829aab88c2f0c1f5009a8d76581604051610e4891815260200190565b60065460405163d09ef24160e01b8152600481018a90525f916001600160a01b03169063d09ef241906024016101e060405180830381865afa1580156112cc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112f09190613250565b8051519091506001600160a01b0316331461131d5760405162461bcd60e51b815260040161030d9061335a565b8051610160015115156001146113455760405162461bcd60e51b815260040161030d90613391565b600654604051635585b19360e01b81526001600160a01b0390911690635585b19390611387908c908c908c908c908c905f9081908e908e908e906004016133bf565b5f604051808303815f87803b15801561139e575f80fd5b505af11580156113b0573d5f803e3d5ffd5b505050507ff6889aa0780be70c770f893999b0adcc2cd01470d2ee0b90f706c5077d93e56b896040516113e591815260200190565b60405180910390a1505050505050505050565b6114006118fd565b5f811161144f5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f604482015260640161030d565b6040516370a0823160e01b815230600482015282905f906001600160a01b038316906370a0823190602401602060405180830381865afa158015611495573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b99190613202565b6040516323b872dd60e01b8152336004820152306024820152604481018590529091506001600160a01b038316906323b872dd906064016020604051808303815f875af115801561150c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061153091906134e8565b61156e5760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161030d565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa1580156115b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d69190613202565b6115e09190613503565b6001600160a01b0385165f9081527f5ccfe41675d26c0b329bf9933f52391aedcc25e23489342bbaefda128a9973d5602052604081208054909190611626908490613438565b909155505050506001600160a01b0382165f8181527f5ccfe41675d26c0b329bf9933f52391aedcc25e23489342bbaefda128a9973d56020908152604080832054338452600180845282852095855294909252822055555050565b5050565b61168d6118fd565b5f81116116dc5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f604482015260640161030d565b335f9081526001602090815260408083206001600160a01b03861684529091529020548111156117455760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b604482015260640161030d565b335f9081526001602090815260408083206001600160a01b038616845290915281208054839290611777908490613503565b909155505060405163a9059cbb60e01b81523360048201526024810182905282906001600160a01b0382169063a9059cbb906044016020604051808303815f875af11580156117c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117ec91906134e8565b61182a5760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161030d565b604080513381526001600160a01b03851660208201529081018390527fa92ff919b850e4909ab2261d907ef955f11bc1716733a6cbece38d163a69af8a9060600160405180910390a15061168160015f55565b5f80826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118bb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118df9190613516565b6118ea90600a613607565b90506118f68382611dea565b9392505050565b60025f540361194e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030d565b60025f55565b5f826119c757335f9081526001602090815260408083206001600160a01b038816845290915290205482116119c057335f9081526001602090815260408083206001600160a01b0388168452909152812080548492906119b5908490613503565b90915550611a229050565b505f611a26565b335f9081526001602090815260408083206001600160a01b038916845290915290205482116119c057335f9081526001602090815260408083206001600160a01b0389168452909152812080548492906119b5908490613503565b5060015b949350505050565b8151608001515f908103611a4d57611a4683836120e9565b9050610978565b611a46838361260e565b5f80611adb845f015160400151855f0151604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb9190613516565b611ad690600a613607565b611dea565b9050805f03611b21576040518381527fbf641aa67d51d72628240e9ac2c9f36cf8c9ec37d043d89382355fe67132e66e906020015b60405180910390a15f915050610978565b5f80808060018851606001516001811115611b3e57611b3e613410565b03611ba157875160e00151851080611b5a5750875160c0015185115b15611ba157875160a0015160408051898152911515602083015281018690525f80516020613792833981519152906060015b60405180910390a15f95505050505050610978565b875160a0015115611c1e575f8851606001516001811115611bc457611bc4613410565b03611c0757875160800151851115611c0757875160a0015160408051898152911515602083015281018690525f8051602061379283398151915290606001611b8c565b875160208101516040909101519094509250611c8c565b5f8851606001516001811115611c3657611c36613410565b03611c7957875160800151851015611c7957875160a0015160408051898152911515602083015281018690525f8051602061379283398151915290606001611b8c565b8751604081015160209091015190945092505b611ca884848a5f015161012001518b5f01516101400151612952565b90925090508015611dba578751516001600160a01b039081165f90815260016020908152604080832093871683529290529081208054849290611cec908490613438565b9091555050600654604051631afd817760e11b81526001600160a01b03909116906335fb02ee90611d24908a90600390600401613615565b5f604051808303815f87803b158015611d3b575f80fd5b505af1158015611d4d573d5f803e3d5ffd5b5050895160a08082015161012090920151604080518d8152931515602085015283015260608201869052608082018990527fd3a2a38532d8ebbcacfb7f0283c81c80740d96318a247267aa64e7ac0a75a57c935001905060405180910390a1600195505050505050610978565b6040518781527ff9e10ddceffcb10b96e8833202366240699b814c91f371ddd9befa3aee9bc60f90602001611b8c565b5f611e0973a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48846108e2565b15611ebb576040805160028082526060820183525f9260208301908036833701905050905083815f81518110611e4157611e41613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881600181518110611e8957611e89613466565b60200260200101906001600160a01b031690816001600160a01b031681525050611eb38184612bd4565b915050610978565b611ed973c28ab4e347dd26c5809540e7db0cea473d91439c846108e2565b15611f59576040805160028082526060820183525f9260208301908036833701905050905083815f81518110611f1157611f11613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073c28ab4e347dd26c5809540e7db0cea473d91439c81600181518110611e8957611e89613466565b611f7773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2846108e2565b1561204157604080516003808252608082019092525f916020820160608036833701905050905083815f81518110611fb157611fb1613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110611ff957611ff9613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881600281518110611e8957611e89613466565b61205f73c5fb36dd2fb59d3b98deff88425a3f425ee469ed846108e2565b156120e157604080516003808252608082019092525f916020820160608036833701905050905083815f8151811061209957612099613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073c5fb36dd2fb59d3b98deff88425a3f425ee469ed81600181518110611ff957611ff9613466565b505f92915050565b5f80612139845f015160400151855f0151604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b9050805f03612172576040518381527fbf641aa67d51d72628240e9ac2c9f36cf8c9ec37d043d89382355fe67132e66e90602001611b10565b83606001511561251957835160e00151811180156121945750835160c0015181105b6121c957835160a0015160408051858152911515602083015281018290525f8051602061379283398151915290606001611b10565b5f805f80875f015160a00151156121f157875160208101516040909101519094509250612204565b8751604081015160209091015190945092505b875161012081015190516001600160a01b039081165f90815260016020908152604080832093891683529290522054106124765761225484848a5f015161012001518b5f01516101400151612952565b90925090508015612446578751516001600160a01b039081165f90815260016020908152604080832093871683529290529081208054849290612298908490613438565b9091555050875161012081015190516001600160a01b039081165f908152600160209081526040808320938916835292905290812080549091906122dd908490613503565b9091555050600654604051631afd817760e11b81526001600160a01b03909116906335fb02ee90612314908a905f90600401613615565b5f604051808303815f87803b15801561232b575f80fd5b505af115801561233d573d5f803e3d5ffd5b5050600654604051620b79f560ea1b8152600481018b90526001600160a01b039091169250632de7d40091506024015f604051808303815f87803b158015612383575f80fd5b505af1158015612395573d5f803e3d5ffd5b5050600654604051635281b98160e01b8152600481018b90525f60248201526001600160a01b039091169250635281b98191506044015f604051808303815f87803b1580156123e2575f80fd5b505af11580156123f4573d5f803e3d5ffd5b5050895160a00151604080518b8152911515602083015281018890527febd85f6b4646b253274fd876529f3b004db9b6f2cb17401ef4afd75f45f4ff23925060600190505b60405180910390a1612510565b6040518781527ff9e10ddceffcb10b96e8833202366240699b814c91f371ddd9befa3aee9bc60f90602001612439565b600654604051631afd817760e11b81526001600160a01b03909116906335fb02ee906124a9908a90600290600401613615565b5f604051808303815f87803b1580156124c0575f80fd5b505af11580156124d2573d5f803e3d5ffd5b505050507f12479fe7346119b9d7b9e673759d5824b3523f69848c8b04d4c7d0e3f194a47f8760405161250791815260200190565b60405180910390a15b50505050610972565b5f60648560400151865f015160e001516125339190613645565b61253d919061365c565b90505f60648660400151875f015160c001516125599190613645565b612563919061365c565b865160e00151909150612577908390613503565b8310806125935750855160c00151612590908290613438565b83115b6125a2575f9350505050610978565b600654604051635281b98160e01b815260048101879052600160248201526001600160a01b0390911690635281b981906044015f604051808303815f87803b1580156125ec575f80fd5b505af11580156125fe573d5f803e3d5ffd5b5050505050505060019392505050565b5f8061265e845f015160400151855f0151604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b9050805f03612697576040518381527fbf641aa67d51d72628240e9ac2c9f36cf8c9ec37d043d89382355fe67132e66e90602001611b10565b835160a00151156127f857836060015115612749578351608001518111156126ea57835160a0015160408051858152911515602083015281018290525f8051602061379283398151915290606001611b10565b835160208082015160408084015161012085015194516001600160a01b039081165f90815260018652838120918516815294529083205491939092918291116124765761225484848a5f015161012001518b5f01516101400151612952565b5f60648560400151865f0151608001516127639190613645565b61276d919061365c565b855160800151909150612781908290613438565b821015612792575f92505050610978565b600654604051635281b98160e01b815260048101869052600160248201526001600160a01b0390911690635281b981906044015f604051808303815f87803b1580156127dc575f80fd5b505af11580156127ee573d5f803e3d5ffd5b5050505050610972565b83606001511561289e5783516080015181101561284057835160a0015160408051858152911515602083015281018290525f8051602061379283398151915290606001611b10565b835160408082015160208084015161012085015194516001600160a01b039081165f908152600184528581209185168152925292812054919390918291116124765761225484848a5f015161012001518b5f01516101400151612952565b5f60648560400151865f0151608001516128b89190613645565b6128c2919061365c565b8551608001519091506128d6908290613503565b8211156128e7575f92505050610978565b600654604051635281b98160e01b815260048101869052600160248201526001600160a01b0390911690635281b981906044015f604051808303815f87803b158015612931575f80fd5b505af1158015612943573d5f803e3d5ffd5b50600198975050505050505050565b60025460405163095ea7b360e01b81526001600160a01b039182166004820152602481018490525f918291879182169063095ea7b3906044016020604051808303815f875af11580156129a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129cb91906134e8565b506040805160028082526060820183525f9260208301908036833701905050905087815f815181106129ff576129ff613466565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600181518110612a3357612a33613466565b6001600160a01b0392831660209182029290920101526040516370a0823160e01b81523060048201525f918916906370a0823190602401602060405180830381865afa158015612a85573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612aa99190613202565b600254604051635c11d79560e01b81529192506001600160a01b031690635c11d79590612ae2908a908a908790309042906004016136bd565b5f604051808303815f87803b158015612af9575f80fd5b505af1925050508015612b0a575060015b612b4c573d808015612b37576040519150601f19603f3d011682016040523d82523d5f602084013e612b3c565b606091505b505f809550955050505050612bcb565b6040516370a0823160e01b81523060048201525f9082906001600160a01b038b16906370a0823190602401602060405180830381865afa158015612b92573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bb69190613202565b612bc09190613503565b955060019450505050505b94509492505050565b60025460405163d06ca61f60e01b81525f9182916001600160a01b039091169063d06ca61f90612c0a90869088906004016136f8565b5f60405180830381865afa158015612c24573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c4b9190810190613710565b90508060018551612c5c9190613503565b81518110612c6c57612c6c613466565b602002602001015191505092915050565b6040518060800160405280612c90612caa565b81526020015f81526020015f81526020015f151581525090565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905290610100820190612c90565b6001600160a01b0381168114612d09575f80fd5b50565b8015158114612d09575f80fd5b5f805f805f8060c08789031215612d2e575f80fd5b8635612d3981612cf5565b95506020870135612d4981612cf5565b94506040870135612d5981612d0c565b959894975094956060810135955060808101359460a0909101359350915050565b5f805f805f805f805f6101208a8c031215612d93575f80fd5b8935985060208a0135612da581612cf5565b975060408a0135612db581612cf5565b965060608a0135612dc581612d0c565b989b979a50959860808101359760a0820135975060c0820135965060e08201359550610100909101359350915050565b5f805f805f805f80610100898b031215612e0d575f80fd5b883597506020890135612e1f81612cf5565b96506040890135612e2f81612cf5565b95506060890135612e3f81612d0c565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b5f60208284031215612e77575f80fd5b81356118f681612cf5565b5f8060408385031215612e93575f80fd5b8235612e9e81612cf5565b91506020830135612eae81612cf5565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff81118282101715612ef057612ef0612eb9565b60405290565b604051610180810167ffffffffffffffff81118282101715612ef057612ef0612eb9565b604051601f8201601f1916810167ffffffffffffffff81118282101715612f4357612f43612eb9565b604052919050565b5f67ffffffffffffffff821115612f6457612f64612eb9565b5060051b60200190565b5f6020808385031215612f7f575f80fd5b823567ffffffffffffffff811115612f95575f80fd5b8301601f81018513612fa5575f80fd5b8035612fb8612fb382612f4b565b612f1a565b81815260059190911b82018301908381019087831115612fd6575f80fd5b928401925b82841015612ff457833582529284019290840190612fdb565b979650505050505050565b5f805f805f805f60e0888a031215613015575f80fd5b87359650602088013561302781612cf5565b9550604088013561303781612cf5565b945060608801359350608088013561304e81612d0c565b9699959850939692959460a0840135945060c09093013592915050565b5f805f805f805f60e0888a031215613081575f80fd5b873561308c81612cf5565b9650602088013561309c81612cf5565b955060408801356130ac81612d0c565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f602082840312156130e4575f80fd5b5035919050565b5f805f805f805f80610100898b031215613103575f80fd5b883561310e81612cf5565b9750602089013561311e81612cf5565b9650604089013561312e81612d0c565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b5f806040838503121561316e575f80fd5b823561317981612cf5565b946020939093013593505050565b60208082526011908201527015985b1a59185d1a5bdb8819985a5b1959607a1b604082015260600190565b6001600160a01b03998a16815297891660208901529590971660408701529215156060860152608085019190915260a084015260c083015260e08201929092526101008101919091526101200190565b5f60208284031215613212575f80fd5b5051919050565b805161322481612cf5565b919050565b805160028110613224575f80fd5b805161322481612d0c565b805160048110613224575f80fd5b5f8183036101e0811215613262575f80fd5b61326a612ecd565b61018080831215613279575f80fd5b613281612ef6565b925061328c85613219565b835261329a60208601613219565b60208401526132ab60408601613219565b60408401526132bc60608601613229565b6060840152608085015160808401526132d760a08601613237565b60a084015260c085015160c084015260e085015160e08401526101006132fe818701613242565b9084015261012085810151908401526101408086015190840152610160613326818701613237565b9084015282825284015160208201526101a0840151604082015261334d6101c08501613237565b6060820152949350505050565b6020808252601d908201527f6d73672e73656e646572206973206e6f74206f72646572206f776e6572000000604082015260600190565b602080825260149082015273496e636f7272656374206f72646572207479706560601b604082015260600190565b998a526001600160a01b0398891660208b01529690971660408901529315156060880152608087019290925260a086015260c085015260e08401526101008301919091526101208201526101400190565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561097857610978613424565b5f6020828403121561345b575f80fd5b81516118f681612cf5565b634e487b7160e01b5f52603260045260245ffd5b5f6001820161348b5761348b613424565b5060010190565b6001600160a01b039a8b168152988a1660208a01529690981660408801529315156060870152608086019290925260a085015260c084015260e08301526101008201929092526101208101919091526101400190565b5f602082840312156134f8575f80fd5b81516118f681612d0c565b8181038181111561097857610978613424565b5f60208284031215613526575f80fd5b815160ff811681146118f6575f80fd5b600181815b8085111561357057815f190482111561355657613556613424565b8085161561356357918102915b93841c939080029061353b565b509250929050565b5f8261358657506001610978565b8161359257505f610978565b816001811461097257600281036135bf5760ff8411156135b4576135b4613424565b50506001821b610978565b5060208310610133831016604e8410600b84101617156135e2575081810a610978565b6135ec8383613536565b805f19048211156135ff576135ff613424565b029392505050565b5f6118f660ff841683613578565b828152604081016004831061363857634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b808202811582820484141761097857610978613424565b5f8261367657634e487b7160e01b5f52601260045260245ffd5b500490565b5f8151808452602080850194508084015f5b838110156136b25781516001600160a01b03168752958201959082019060010161368d565b509495945050505050565b85815284602082015260a060408201525f6136db60a083018661367b565b6001600160a01b0394909416606083015250608001529392505050565b828152604060208201525f611a26604083018461367b565b5f6020808385031215613721575f80fd5b825167ffffffffffffffff811115613737575f80fd5b8301601f81018513613747575f80fd5b8051613755612fb382612f4b565b81815260059190911b82018301908381019087831115613773575f80fd5b928401925b82841015612ff45783518252928401929084019061377856fe376cc40e122623406a50cd32e6ec71ccc664eb3ea2107e8db1822d3b9cfac54aa264697066735822122097112d2a6fb89b0ec872c67e233bd3b9939943f57c42bce9e86566a37a0f867764736f6c63430008150033

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061011c575f3560e01c8063514fcac7116100a9578063bc4b33651161006e578063bc4b336514610259578063c10753291461026c578063c23f001f1461027f578063d02641a0146102b7578063f77d4631146102ca575f80fd5b8063514fcac7146101fa5780635d58b7561461020d578063754dea40146102205780637720f717146102335780638bd4185814610246575f80fd5b806338800428116100ef578063388004281461016e5780633d1246d01461019e57806341929f0f146101c1578063441106c9146101d4578063452c4875146101e7575f80fd5b80630848a3c7146101205780630d48317b14610135578063209f90c3146101485780632b0b06621461015b575b5f80fd5b61013361012e366004612d19565b6102dd565b005b610133610143366004612d7a565b6103e3565b610133610156366004612df5565b610558565b610133610169366004612e67565b6107fa565b600554610181906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6101b16101ac366004612e82565b6108e2565b6040519015158152602001610195565b6101336101cf366004612f6e565b61097e565b6101336101e2366004612fff565b610aea565b6101336101f536600461306b565b610d8b565b6101336102083660046130d4565b610e5a565b61013361021b3660046130eb565b611038565b61013361022e366004612e67565b611107565b61013361024136600461306b565b6111a1565b610133610254366004612df5565b611284565b61013361026736600461315d565b6113f8565b61013361027a36600461315d565b611685565b6102a961028d366004612e82565b600160209081525f928352604080842090915290825290205481565b604051908152602001610195565b6102a96102c5366004612e67565b61187d565b600454610181906001600160a01b031681565b6102e56118fd565b6102f186868685611954565b6103165760405162461bcd60e51b815260040161030d90613187565b60405180910390fd5b600654604051630d570f1560e31b81525f916001600160a01b031690636ab878a8906103569033908b908b908b908b90899081908d908d906004016131b2565b6020604051808303815f875af1158015610372573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103969190613202565b90507f7ae91fe4742a77fb791e82e77c1b02800bd8fc0829aab88c2f0c1f5009a8d765816040516103c991815260200190565b60405180910390a1506103db60015f55565b505050505050565b60065460405163d09ef24160e01b8152600481018b90525f916001600160a01b03169063d09ef241906024016101e060405180830381865afa15801561042b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061044f9190613250565b8051519091506001600160a01b0316331461047c5760405162461bcd60e51b815260040161030d9061335a565b8051610160015115156001146104a45760405162461bcd60e51b815260040161030d90613391565b600654604051635585b19360e01b81526001600160a01b0390911690635585b193906104e6908d908d908d908d905f908e908e908e908e908e906004016133bf565b5f604051808303815f87803b1580156104fd575f80fd5b505af115801561050f573d5f803e3d5ffd5b505050507ff6889aa0780be70c770f893999b0adcc2cd01470d2ee0b90f706c5077d93e56b8a60405161054491815260200190565b60405180910390a150505050505050505050565b6105606118fd565b60065460405163d09ef24160e01b8152600481018a905289915f916001600160a01b039091169063d09ef241906024016101e060405180830381865afa1580156105ac573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105d09190613250565b8051519091506001600160a01b031633146105fd5760405162461bcd60e51b815260040161030d9061335a565b80516101600151156106215760405162461bcd60e51b815260040161030d90613391565b5f81516101000151600381111561063a5761063a613410565b146106805760405162461bcd60e51b8152602060048201526016602482015275496e636f7272656374206f726465722073746174757360501b604482015260640161030d565b805160a001516106d25780516101200151335f90815260016020908152604080832085518201516001600160a01b03168452909152812080549091906106c7908490613438565b909155506107159050565b80516101200151335f90815260016020908152604080832085518301516001600160a01b031684529091528120805490919061070f908490613438565b90915550505b61072189898987611954565b61073d5760405162461bcd60e51b815260040161030d90613187565b600654604051635585b19360e01b81526001600160a01b0390911690635585b1939061077f908d908d908d908d905f908e908e908e908e9085906004016133bf565b5f604051808303815f87803b158015610796575f80fd5b505af11580156107a8573d5f803e3d5ffd5b505050507ff7f893fb8cda745632d6c27ec518a84338faeb6dbc795efb4cd00d29638610b38a6040516107dd91815260200190565b60405180910390a150506107f060015f55565b5050505050505050565b6004546001600160a01b031633146108545760405162461bcd60e51b815260206004820152601860248201527f7365744f726465724d67723a206e6f7420616c6c6f7765640000000000000000604482015260640161030d565b6001600160a01b0381166108b65760405162461bcd60e51b8152602060048201526024808201527f7365744f726465724d67723a20696e76616c6964206f726465724d67724164646044820152637265737360e01b606482015260840161030d565b600580546001600160a01b039092166001600160a01b0319928316811790915560068054909216179055565b60035460405163e6a4390560e01b81526001600160a01b03848116600483015283811660248301525f92839291169063e6a4390590604401602060405180830381865afa158015610935573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610959919061344b565b90506001600160a01b038116610972575f915050610978565b60019150505b92915050565b610986612c7d565b5f5b8251811015610ae55760065483516001600160a01b039091169063d09ef241908590849081106109ba576109ba613466565b60200260200101516040518263ffffffff1660e01b81526004016109e091815260200190565b6101e060405180830381865afa1580156109fc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a209190613250565b91505f838281518110610a3557610a35613466565b60209081029190910101518351604001519091506001600160a01b0316610a5c5750610ad3565b825161016001511515600103610aa1576001835161010001516003811115610a8657610a86613410565b03610a915750610ad3565b610a9b8382611a2e565b50610ad1565b5f835161010001516003811115610aba57610aba613410565b14610ac55750610ad3565b610acf8382611a57565b505b505b80610add8161347a565b915050610988565b505050565b610af26118fd565b60065460405163d09ef24160e01b81526004810189905288915f916001600160a01b039091169063d09ef241906024016101e060405180830381865afa158015610b3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b629190613250565b8051519091506001600160a01b03163314610b8f5760405162461bcd60e51b815260040161030d9061335a565b8051610160015115610bb35760405162461bcd60e51b815260040161030d90613391565b5f815161010001516003811115610bcc57610bcc613410565b14610c125760405162461bcd60e51b8152602060048201526016602482015275496e636f7272656374206f726465722073746174757360501b604482015260640161030d565b805160a00151610c645780516101200151335f90815260016020908152604080832085518201516001600160a01b0316845290915281208054909190610c59908490613438565b90915550610ca79050565b80516101200151335f90815260016020908152604080832085518301516001600160a01b0316845290915281208054909190610ca1908490613438565b90915550505b610cb388888787611954565b610ccf5760405162461bcd60e51b815260040161030d90613187565b600654604051635585b19360e01b81526001600160a01b0390911690635585b19390610d11908c908c908c908b908d905f9081908e908e9083906004016133bf565b5f604051808303815f87803b158015610d28575f80fd5b505af1158015610d3a573d5f803e3d5ffd5b505050507ff7f893fb8cda745632d6c27ec518a84338faeb6dbc795efb4cd00d29638610b389604051610d6f91815260200190565b60405180910390a15050610d8260015f55565b50505050505050565b610d936118fd565b60065460405163d6f35bd560e01b81525f916001600160a01b03169063d6f35bd590610dd59033908c908c908c908c90899081908e908e908e90600401613492565b6020604051808303815f875af1158015610df1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e159190613202565b90507ff40951d004ae9ba03a1b52a13452626d3bbb2cd7a662dab67f84e8b564a9a06781604051610e4891815260200190565b60405180910390a150610d8260015f55565b60065460405163d09ef24160e01b8152600481018390525f916001600160a01b03169063d09ef241906024016101e060405180830381865afa158015610ea2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ec69190613250565b8051519091506001600160a01b03163314610ef35760405162461bcd60e51b815260040161030d9061335a565b60065460405163514fcac760e01b8152600481018490526001600160a01b039091169063514fcac7906024016020604051808303815f875af1158015610f3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f5f9190613202565b508051610160015161100157805160a0015115610fbe5780516101200151335f90815260016020908152604080832085518301516001600160a01b0316845290915281208054909190610fb3908490613438565b909155506110019050565b80516101200151335f90815260016020908152604080832085518201516001600160a01b0316845290915281208054909190610ffb908490613438565b90915550505b6040518281527fc41f4ceb2938876c35e61b705e9d2f18a02c4a26ce5e049a6308a943d46851b39060200160405180910390a15050565b6110406118fd565b60065460405163d6f35bd560e01b81525f916001600160a01b03169063d6f35bd5906110829033908d908d908d9088908e908e908e908e908e90600401613492565b6020604051808303815f875af115801561109e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110c29190613202565b90507ff40951d004ae9ba03a1b52a13452626d3bbb2cd7a662dab67f84e8b564a9a067816040516110f591815260200190565b60405180910390a1506107f060015f55565b6004546001600160a01b0316331461114d5760405162461bcd60e51b81526020600482015260096024820152682737ba1030b236b4b760b91b604482015260640161030d565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f57a2989fbcdc251cf10758ea804ebbbd61e9da58a859d3fbf6bcfdd9c31bec7e9060200160405180910390a150565b6111a96118fd565b6111b587878785611954565b6111d15760405162461bcd60e51b815260040161030d90613187565b600654604051630d570f1560e31b81525f916001600160a01b031690636ab878a8906112119033908c908c908c9088908d908d908d908d906004016131b2565b6020604051808303815f875af115801561122d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112519190613202565b90507f7ae91fe4742a77fb791e82e77c1b02800bd8fc0829aab88c2f0c1f5009a8d76581604051610e4891815260200190565b60065460405163d09ef24160e01b8152600481018a90525f916001600160a01b03169063d09ef241906024016101e060405180830381865afa1580156112cc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112f09190613250565b8051519091506001600160a01b0316331461131d5760405162461bcd60e51b815260040161030d9061335a565b8051610160015115156001146113455760405162461bcd60e51b815260040161030d90613391565b600654604051635585b19360e01b81526001600160a01b0390911690635585b19390611387908c908c908c908c908c905f9081908e908e908e906004016133bf565b5f604051808303815f87803b15801561139e575f80fd5b505af11580156113b0573d5f803e3d5ffd5b505050507ff6889aa0780be70c770f893999b0adcc2cd01470d2ee0b90f706c5077d93e56b896040516113e591815260200190565b60405180910390a1505050505050505050565b6114006118fd565b5f811161144f5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f604482015260640161030d565b6040516370a0823160e01b815230600482015282905f906001600160a01b038316906370a0823190602401602060405180830381865afa158015611495573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114b99190613202565b6040516323b872dd60e01b8152336004820152306024820152604481018590529091506001600160a01b038316906323b872dd906064016020604051808303815f875af115801561150c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061153091906134e8565b61156e5760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161030d565b6040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa1580156115b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115d69190613202565b6115e09190613503565b6001600160a01b0385165f9081527f5ccfe41675d26c0b329bf9933f52391aedcc25e23489342bbaefda128a9973d5602052604081208054909190611626908490613438565b909155505050506001600160a01b0382165f8181527f5ccfe41675d26c0b329bf9933f52391aedcc25e23489342bbaefda128a9973d56020908152604080832054338452600180845282852095855294909252822055555050565b5050565b61168d6118fd565b5f81116116dc5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74206d7573742062652067726561746572207468616e207a65726f604482015260640161030d565b335f9081526001602090815260408083206001600160a01b03861684529091529020548111156117455760405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b604482015260640161030d565b335f9081526001602090815260408083206001600160a01b038616845290915281208054839290611777908490613503565b909155505060405163a9059cbb60e01b81523360048201526024810182905282906001600160a01b0382169063a9059cbb906044016020604051808303815f875af11580156117c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117ec91906134e8565b61182a5760405162461bcd60e51b815260206004820152600f60248201526e151c985b9cd9995c8819985a5b1959608a1b604482015260640161030d565b604080513381526001600160a01b03851660208201529081018390527fa92ff919b850e4909ab2261d907ef955f11bc1716733a6cbece38d163a69af8a9060600160405180910390a15061168160015f55565b5f80826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118bb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118df9190613516565b6118ea90600a613607565b90506118f68382611dea565b9392505050565b60025f540361194e5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161030d565b60025f55565b5f826119c757335f9081526001602090815260408083206001600160a01b038816845290915290205482116119c057335f9081526001602090815260408083206001600160a01b0388168452909152812080548492906119b5908490613503565b90915550611a229050565b505f611a26565b335f9081526001602090815260408083206001600160a01b038916845290915290205482116119c057335f9081526001602090815260408083206001600160a01b0389168452909152812080548492906119b5908490613503565b5060015b949350505050565b8151608001515f908103611a4d57611a4683836120e9565b9050610978565b611a46838361260e565b5f80611adb845f015160400151855f0151604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611acb9190613516565b611ad690600a613607565b611dea565b9050805f03611b21576040518381527fbf641aa67d51d72628240e9ac2c9f36cf8c9ec37d043d89382355fe67132e66e906020015b60405180910390a15f915050610978565b5f80808060018851606001516001811115611b3e57611b3e613410565b03611ba157875160e00151851080611b5a5750875160c0015185115b15611ba157875160a0015160408051898152911515602083015281018690525f80516020613792833981519152906060015b60405180910390a15f95505050505050610978565b875160a0015115611c1e575f8851606001516001811115611bc457611bc4613410565b03611c0757875160800151851115611c0757875160a0015160408051898152911515602083015281018690525f8051602061379283398151915290606001611b8c565b875160208101516040909101519094509250611c8c565b5f8851606001516001811115611c3657611c36613410565b03611c7957875160800151851015611c7957875160a0015160408051898152911515602083015281018690525f8051602061379283398151915290606001611b8c565b8751604081015160209091015190945092505b611ca884848a5f015161012001518b5f01516101400151612952565b90925090508015611dba578751516001600160a01b039081165f90815260016020908152604080832093871683529290529081208054849290611cec908490613438565b9091555050600654604051631afd817760e11b81526001600160a01b03909116906335fb02ee90611d24908a90600390600401613615565b5f604051808303815f87803b158015611d3b575f80fd5b505af1158015611d4d573d5f803e3d5ffd5b5050895160a08082015161012090920151604080518d8152931515602085015283015260608201869052608082018990527fd3a2a38532d8ebbcacfb7f0283c81c80740d96318a247267aa64e7ac0a75a57c935001905060405180910390a1600195505050505050610978565b6040518781527ff9e10ddceffcb10b96e8833202366240699b814c91f371ddd9befa3aee9bc60f90602001611b8c565b5f611e0973a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48846108e2565b15611ebb576040805160028082526060820183525f9260208301908036833701905050905083815f81518110611e4157611e41613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881600181518110611e8957611e89613466565b60200260200101906001600160a01b031690816001600160a01b031681525050611eb38184612bd4565b915050610978565b611ed973c28ab4e347dd26c5809540e7db0cea473d91439c846108e2565b15611f59576040805160028082526060820183525f9260208301908036833701905050905083815f81518110611f1157611f11613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073c28ab4e347dd26c5809540e7db0cea473d91439c81600181518110611e8957611e89613466565b611f7773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2846108e2565b1561204157604080516003808252608082019092525f916020820160608036833701905050905083815f81518110611fb157611fb1613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110611ff957611ff9613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881600281518110611e8957611e89613466565b61205f73c5fb36dd2fb59d3b98deff88425a3f425ee469ed846108e2565b156120e157604080516003808252608082019092525f916020820160608036833701905050905083815f8151811061209957612099613466565b60200260200101906001600160a01b031690816001600160a01b03168152505073c5fb36dd2fb59d3b98deff88425a3f425ee469ed81600181518110611ff957611ff9613466565b505f92915050565b5f80612139845f015160400151855f0151604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b9050805f03612172576040518381527fbf641aa67d51d72628240e9ac2c9f36cf8c9ec37d043d89382355fe67132e66e90602001611b10565b83606001511561251957835160e00151811180156121945750835160c0015181105b6121c957835160a0015160408051858152911515602083015281018290525f8051602061379283398151915290606001611b10565b5f805f80875f015160a00151156121f157875160208101516040909101519094509250612204565b8751604081015160209091015190945092505b875161012081015190516001600160a01b039081165f90815260016020908152604080832093891683529290522054106124765761225484848a5f015161012001518b5f01516101400151612952565b90925090508015612446578751516001600160a01b039081165f90815260016020908152604080832093871683529290529081208054849290612298908490613438565b9091555050875161012081015190516001600160a01b039081165f908152600160209081526040808320938916835292905290812080549091906122dd908490613503565b9091555050600654604051631afd817760e11b81526001600160a01b03909116906335fb02ee90612314908a905f90600401613615565b5f604051808303815f87803b15801561232b575f80fd5b505af115801561233d573d5f803e3d5ffd5b5050600654604051620b79f560ea1b8152600481018b90526001600160a01b039091169250632de7d40091506024015f604051808303815f87803b158015612383575f80fd5b505af1158015612395573d5f803e3d5ffd5b5050600654604051635281b98160e01b8152600481018b90525f60248201526001600160a01b039091169250635281b98191506044015f604051808303815f87803b1580156123e2575f80fd5b505af11580156123f4573d5f803e3d5ffd5b5050895160a00151604080518b8152911515602083015281018890527febd85f6b4646b253274fd876529f3b004db9b6f2cb17401ef4afd75f45f4ff23925060600190505b60405180910390a1612510565b6040518781527ff9e10ddceffcb10b96e8833202366240699b814c91f371ddd9befa3aee9bc60f90602001612439565b600654604051631afd817760e11b81526001600160a01b03909116906335fb02ee906124a9908a90600290600401613615565b5f604051808303815f87803b1580156124c0575f80fd5b505af11580156124d2573d5f803e3d5ffd5b505050507f12479fe7346119b9d7b9e673759d5824b3523f69848c8b04d4c7d0e3f194a47f8760405161250791815260200190565b60405180910390a15b50505050610972565b5f60648560400151865f015160e001516125339190613645565b61253d919061365c565b90505f60648660400151875f015160c001516125599190613645565b612563919061365c565b865160e00151909150612577908390613503565b8310806125935750855160c00151612590908290613438565b83115b6125a2575f9350505050610978565b600654604051635281b98160e01b815260048101879052600160248201526001600160a01b0390911690635281b981906044015f604051808303815f87803b1580156125ec575f80fd5b505af11580156125fe573d5f803e3d5ffd5b5050505050505060019392505050565b5f8061265e845f015160400151855f0151604001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611aa7573d5f803e3d5ffd5b9050805f03612697576040518381527fbf641aa67d51d72628240e9ac2c9f36cf8c9ec37d043d89382355fe67132e66e90602001611b10565b835160a00151156127f857836060015115612749578351608001518111156126ea57835160a0015160408051858152911515602083015281018290525f8051602061379283398151915290606001611b10565b835160208082015160408084015161012085015194516001600160a01b039081165f90815260018652838120918516815294529083205491939092918291116124765761225484848a5f015161012001518b5f01516101400151612952565b5f60648560400151865f0151608001516127639190613645565b61276d919061365c565b855160800151909150612781908290613438565b821015612792575f92505050610978565b600654604051635281b98160e01b815260048101869052600160248201526001600160a01b0390911690635281b981906044015f604051808303815f87803b1580156127dc575f80fd5b505af11580156127ee573d5f803e3d5ffd5b5050505050610972565b83606001511561289e5783516080015181101561284057835160a0015160408051858152911515602083015281018290525f8051602061379283398151915290606001611b10565b835160408082015160208084015161012085015194516001600160a01b039081165f908152600184528581209185168152925292812054919390918291116124765761225484848a5f015161012001518b5f01516101400151612952565b5f60648560400151865f0151608001516128b89190613645565b6128c2919061365c565b8551608001519091506128d6908290613503565b8211156128e7575f92505050610978565b600654604051635281b98160e01b815260048101869052600160248201526001600160a01b0390911690635281b981906044015f604051808303815f87803b158015612931575f80fd5b505af1158015612943573d5f803e3d5ffd5b50600198975050505050505050565b60025460405163095ea7b360e01b81526001600160a01b039182166004820152602481018490525f918291879182169063095ea7b3906044016020604051808303815f875af11580156129a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129cb91906134e8565b506040805160028082526060820183525f9260208301908036833701905050905087815f815181106129ff576129ff613466565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600181518110612a3357612a33613466565b6001600160a01b0392831660209182029290920101526040516370a0823160e01b81523060048201525f918916906370a0823190602401602060405180830381865afa158015612a85573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612aa99190613202565b600254604051635c11d79560e01b81529192506001600160a01b031690635c11d79590612ae2908a908a908790309042906004016136bd565b5f604051808303815f87803b158015612af9575f80fd5b505af1925050508015612b0a575060015b612b4c573d808015612b37576040519150601f19603f3d011682016040523d82523d5f602084013e612b3c565b606091505b505f809550955050505050612bcb565b6040516370a0823160e01b81523060048201525f9082906001600160a01b038b16906370a0823190602401602060405180830381865afa158015612b92573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bb69190613202565b612bc09190613503565b955060019450505050505b94509492505050565b60025460405163d06ca61f60e01b81525f9182916001600160a01b039091169063d06ca61f90612c0a90869088906004016136f8565b5f60405180830381865afa158015612c24573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c4b9190810190613710565b90508060018551612c5c9190613503565b81518110612c6c57612c6c613466565b602002602001015191505092915050565b6040518060800160405280612c90612caa565b81526020015f81526020015f81526020015f151581525090565b60408051610180810182525f80825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905290610100820190612c90565b6001600160a01b0381168114612d09575f80fd5b50565b8015158114612d09575f80fd5b5f805f805f8060c08789031215612d2e575f80fd5b8635612d3981612cf5565b95506020870135612d4981612cf5565b94506040870135612d5981612d0c565b959894975094956060810135955060808101359460a0909101359350915050565b5f805f805f805f805f6101208a8c031215612d93575f80fd5b8935985060208a0135612da581612cf5565b975060408a0135612db581612cf5565b965060608a0135612dc581612d0c565b989b979a50959860808101359760a0820135975060c0820135965060e08201359550610100909101359350915050565b5f805f805f805f80610100898b031215612e0d575f80fd5b883597506020890135612e1f81612cf5565b96506040890135612e2f81612cf5565b95506060890135612e3f81612d0c565b979a969950949760808101359660a0820135965060c0820135955060e0909101359350915050565b5f60208284031215612e77575f80fd5b81356118f681612cf5565b5f8060408385031215612e93575f80fd5b8235612e9e81612cf5565b91506020830135612eae81612cf5565b809150509250929050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff81118282101715612ef057612ef0612eb9565b60405290565b604051610180810167ffffffffffffffff81118282101715612ef057612ef0612eb9565b604051601f8201601f1916810167ffffffffffffffff81118282101715612f4357612f43612eb9565b604052919050565b5f67ffffffffffffffff821115612f6457612f64612eb9565b5060051b60200190565b5f6020808385031215612f7f575f80fd5b823567ffffffffffffffff811115612f95575f80fd5b8301601f81018513612fa5575f80fd5b8035612fb8612fb382612f4b565b612f1a565b81815260059190911b82018301908381019087831115612fd6575f80fd5b928401925b82841015612ff457833582529284019290840190612fdb565b979650505050505050565b5f805f805f805f60e0888a031215613015575f80fd5b87359650602088013561302781612cf5565b9550604088013561303781612cf5565b945060608801359350608088013561304e81612d0c565b9699959850939692959460a0840135945060c09093013592915050565b5f805f805f805f60e0888a031215613081575f80fd5b873561308c81612cf5565b9650602088013561309c81612cf5565b955060408801356130ac81612d0c565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f602082840312156130e4575f80fd5b5035919050565b5f805f805f805f80610100898b031215613103575f80fd5b883561310e81612cf5565b9750602089013561311e81612cf5565b9650604089013561312e81612d0c565b979a96995096976060810135975060808101359660a0820135965060c0820135955060e0909101359350915050565b5f806040838503121561316e575f80fd5b823561317981612cf5565b946020939093013593505050565b60208082526011908201527015985b1a59185d1a5bdb8819985a5b1959607a1b604082015260600190565b6001600160a01b03998a16815297891660208901529590971660408701529215156060860152608085019190915260a084015260c083015260e08201929092526101008101919091526101200190565b5f60208284031215613212575f80fd5b5051919050565b805161322481612cf5565b919050565b805160028110613224575f80fd5b805161322481612d0c565b805160048110613224575f80fd5b5f8183036101e0811215613262575f80fd5b61326a612ecd565b61018080831215613279575f80fd5b613281612ef6565b925061328c85613219565b835261329a60208601613219565b60208401526132ab60408601613219565b60408401526132bc60608601613229565b6060840152608085015160808401526132d760a08601613237565b60a084015260c085015160c084015260e085015160e08401526101006132fe818701613242565b9084015261012085810151908401526101408086015190840152610160613326818701613237565b9084015282825284015160208201526101a0840151604082015261334d6101c08501613237565b6060820152949350505050565b6020808252601d908201527f6d73672e73656e646572206973206e6f74206f72646572206f776e6572000000604082015260600190565b602080825260149082015273496e636f7272656374206f72646572207479706560601b604082015260600190565b998a526001600160a01b0398891660208b01529690971660408901529315156060880152608087019290925260a086015260c085015260e08401526101008301919091526101208201526101400190565b634e487b7160e01b5f52602160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b8082018082111561097857610978613424565b5f6020828403121561345b575f80fd5b81516118f681612cf5565b634e487b7160e01b5f52603260045260245ffd5b5f6001820161348b5761348b613424565b5060010190565b6001600160a01b039a8b168152988a1660208a01529690981660408801529315156060870152608086019290925260a085015260c084015260e08301526101008201929092526101208101919091526101400190565b5f602082840312156134f8575f80fd5b81516118f681612d0c565b8181038181111561097857610978613424565b5f60208284031215613526575f80fd5b815160ff811681146118f6575f80fd5b600181815b8085111561357057815f190482111561355657613556613424565b8085161561356357918102915b93841c939080029061353b565b509250929050565b5f8261358657506001610978565b8161359257505f610978565b816001811461097257600281036135bf5760ff8411156135b4576135b4613424565b50506001821b610978565b5060208310610133831016604e8410600b84101617156135e2575081810a610978565b6135ec8383613536565b805f19048211156135ff576135ff613424565b029392505050565b5f6118f660ff841683613578565b828152604081016004831061363857634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b808202811582820484141761097857610978613424565b5f8261367657634e487b7160e01b5f52601260045260245ffd5b500490565b5f8151808452602080850194508084015f5b838110156136b25781516001600160a01b03168752958201959082019060010161368d565b509495945050505050565b85815284602082015260a060408201525f6136db60a083018661367b565b6001600160a01b0394909416606083015250608001529392505050565b828152604060208201525f611a26604083018461367b565b5f6020808385031215613721575f80fd5b825167ffffffffffffffff811115613737575f80fd5b8301601f81018513613747575f80fd5b8051613755612fb382612f4b565b81815260059190911b82018301908381019087831115613773575f80fd5b928401925b82841015612ff45783518252928401929084019061377856fe376cc40e122623406a50cd32e6ec71ccc664eb3ea2107e8db1822d3b9cfac54aa264697066735822122097112d2a6fb89b0ec872c67e233bd3b9939943f57c42bce9e86566a37a0f867764736f6c63430008150033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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