Address Details
contract

0xB792AC2E6c4B74892dCD87a3D3F242052bF79ECd

Contract Name
DCA
Creator
0xe59f13–f1e2b8 at 0xe789ee–e78341
Balance
0.004907976124116925 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
9 Transactions
Transfers
14 Transfers
Gas Used
1,261,209
Last Balance Update
13565737
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
DCA




Optimization enabled
true
Compiler version
v0.8.13+commit.abaa5c0e




Optimization runs
999999
EVM Version
london




Verified at
2022-06-16T19:23:51.699723Z

contracts/DCA.sol

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "./interfaces/ISwapper.sol";
import "./interfaces/IOracle.sol";

contract DCA is Ownable {
    uint256 public constant BLOCKS_PER_DAY = 17280;
    uint256 public constant MAX_FEE_NUMERATOR = 6_000; // max 60 bps.
    uint256 public constant FEE_DENOMINATOR = 1_000_000;

    event OrderCreated(
        address indexed userAddress,
        uint256 index,
        IERC20 indexed sellToken,
        IERC20 indexed buyToken,
        uint256 amountPerSwap,
        uint256 numberOfSwaps,
        uint256 startingPeriod
    );
    event SwapExecuted(
        address indexed sellToken,
        address indexed buyToken,
        uint256 sellAmount,
        uint256 buyAmount,
        uint256 indexed period
    );
    event SwappedWithdrawal(
        address indexed userAddress,
        uint256 indexed index,
        address indexed token,
        uint256 amount
    );
    event RemainingWithdrawal(
        address indexed userAddress,
        uint256 indexed index,
        address indexed token,
        uint256 amount
    );
    event TokenPairInitialized(address sellToken, address buyToken);
    event EmergencyWithdrawal(address token, uint256 amount, address to);
    event OracleSet(address oracle);
    event OracleAddressMappingSet(address from, address to);
    event BeneficiarySet(address newBeneficiary);
    event FeeNumeratorSet(uint256 feeNumerator);

    struct UserOrder {
        IERC20 sellToken;
        IERC20 buyToken;
        uint256 amountPerSwap;
        uint256 numberOfSwaps;
        uint256 startingPeriod;
        uint256 lastPeriodWithdrawal;
    }

    struct SwapOrder {
        uint256 amountToSwap;
        uint256 lastPeriod;
        // For each past period, what exchange rate was used.
        mapping(uint256 => uint256) swapExchangeRates;
        // For each future period, how much to reduce to |amountToSwap|.
        mapping(uint256 => uint256) amountsToReduce;
    }

    // sellToken => buyToken => SwapOrder
    mapping(address => mapping(address => SwapOrder)) public swapOrders;
    // userAddress => UserOrder list
    mapping(address => UserOrder[]) public orders;
    // For cUSD, we need to use mcUSD in the oracle because of Ubeswap liquidity. Same with cEUR/cREAL.
    mapping(address => address) public oracleAddresses;

    uint256 public feeNumerator;
    address public beneficiary;
    Oracle public oracle;

    constructor(
        Oracle _oracle,
        address _beneficiary,
        uint256 initialFee
    ) {
        setOracle(_oracle);
        setBeneficiary(_beneficiary);
        setFeeNumerator(initialFee);
    }

    function createOrder(
        IERC20 _sellToken,
        IERC20 _buyToken,
        uint256 _amountPerSwap,
        uint256 _numberOfSwaps
    ) external returns (uint256 index) {
        require(
            _sellToken.transferFrom(
                msg.sender,
                address(this),
                _amountPerSwap * _numberOfSwaps
            ),
            "DCA: Not enough funds"
        );

        SwapOrder storage swapOrder = swapOrders[address(_sellToken)][
            address(_buyToken)
        ];
        if (swapOrder.lastPeriod == 0) {
            swapOrder.lastPeriod = getCurrentPeriod() - 1;
            emit TokenPairInitialized(address(_sellToken), address(_buyToken));
        }
        uint256 startingPeriod = swapOrder.lastPeriod + 1;
        UserOrder memory newOrder = UserOrder(
            _sellToken,
            _buyToken,
            _amountPerSwap,
            _numberOfSwaps,
            startingPeriod,
            swapOrder.lastPeriod
        );

        swapOrder.amountToSwap += _amountPerSwap;
        swapOrder.amountsToReduce[
            startingPeriod + _numberOfSwaps - 1
        ] += _amountPerSwap;

        index = orders[msg.sender].length;
        orders[msg.sender].push(newOrder);

        emit OrderCreated(
            msg.sender,
            index,
            _sellToken,
            _buyToken,
            _amountPerSwap,
            _numberOfSwaps,
            startingPeriod
        );
    }

    function executeOrder(
        address _sellToken,
        address _buyToken,
        uint256 _period,
        address _swapper,
        bytes memory _params
    ) external {
        SwapOrder storage swapOrder = swapOrders[_sellToken][_buyToken];
        require(swapOrder.lastPeriod + 1 == _period, "DCA: Invalid period");
        require(
            _period <= getCurrentPeriod(),
            "DCA: Period cannot be in the future"
        );
        uint256 fee = (swapOrder.amountToSwap * feeNumerator) / FEE_DENOMINATOR;
        uint256 swapAmount = swapOrder.amountToSwap - fee;

        uint256 requiredAmount = oracle.consult(
            getOracleTokenAddress(_sellToken),
            swapAmount,
            getOracleTokenAddress(_buyToken)
        );
        require(requiredAmount > 0, "DCA: Oracle failure");

        swapOrder.lastPeriod++;
        swapOrder.swapExchangeRates[_period] =
            (requiredAmount * 1e18) /
            swapAmount;
        swapOrder.amountToSwap -= swapOrder.amountsToReduce[_period];

        require(
            IERC20(_sellToken).transfer(beneficiary, fee),
            "DCA: Fee transfer to beneficiary failed"
        );

        uint256 balanceBefore = IERC20(_buyToken).balanceOf(address(this));
        require(
            IERC20(_sellToken).transfer(_swapper, swapAmount),
            "DCA: Transfer to Swapper failed"
        );
        ISwapper(_swapper).swap(
            _sellToken,
            _buyToken,
            swapAmount,
            requiredAmount,
            _params
        );
        require(
            balanceBefore + requiredAmount <=
                IERC20(_buyToken).balanceOf(address(this)),
            "DCA: Not enough balance returned"
        );

        emit SwapExecuted(
            _sellToken,
            _buyToken,
            swapAmount,
            requiredAmount,
            _period
        );
    }

    function withdrawSwapped(uint256 index) public {
        UserOrder storage order = orders[msg.sender][index];
        (
            uint256 amountToWithdraw,
            uint256 finalPeriod
        ) = calculateAmountToWithdraw(order);
        order.lastPeriodWithdrawal = finalPeriod;

        require(
            order.buyToken.transfer(msg.sender, amountToWithdraw),
            "DCA: Not enough funds to withdraw"
        );

        emit SwappedWithdrawal(
            msg.sender,
            index,
            address(order.buyToken),
            amountToWithdraw
        );
    }

    function withdrawAll(uint256 index) external {
        withdrawSwapped(index);

        UserOrder storage order = orders[msg.sender][index];
        SwapOrder storage swapOrder = swapOrders[address(order.sellToken)][
            address(order.buyToken)
        ];

        uint256 finalPeriod = order.startingPeriod + order.numberOfSwaps - 1;

        if (finalPeriod > swapOrder.lastPeriod) {
            swapOrder.amountToSwap -= order.amountPerSwap;
            swapOrder.amountsToReduce[finalPeriod] -= order.amountPerSwap;
            uint256 amountToWithdraw = order.amountPerSwap *
                (finalPeriod - swapOrder.lastPeriod);
            order.lastPeriodWithdrawal = finalPeriod;

            require(
                order.sellToken.transfer(msg.sender, amountToWithdraw),
                "DCA: Not enough funds to withdraw"
            );

            emit RemainingWithdrawal(
                msg.sender,
                index,
                address(order.sellToken),
                amountToWithdraw
            );
        }
    }

    function emergencyWithdrawal(IERC20 token, address to) external onlyOwner {
        uint256 balance = token.balanceOf(address(this));
        require(token.transfer(to, balance), "DCA: Emergency transfer failed");
        emit EmergencyWithdrawal(address(token), balance, to);
    }

    // Parameter setters

    function setOracle(Oracle _newOracle) public onlyOwner {
        oracle = _newOracle;
        emit OracleSet(address(oracle));
    }

    function setBeneficiary(address _beneficiary) public onlyOwner {
        beneficiary = _beneficiary;
        emit BeneficiarySet(_beneficiary);
    }

    function setFeeNumerator(uint256 _feeNumerator) public onlyOwner {
        feeNumerator = _feeNumerator;
        emit FeeNumeratorSet(_feeNumerator);
    }

    function addAddressMapping(address _from, address _to) external onlyOwner {
        oracleAddresses[_from] = _to;
        emit OracleAddressMappingSet(_from, _to);
    }

    // Views

    function calculateAmountToWithdraw(UserOrder memory order)
        public
        view
        returns (uint256 amountToWithdraw, uint256 finalPeriod)
    {
        SwapOrder storage swapOrder = swapOrders[address(order.sellToken)][
            address(order.buyToken)
        ];
        finalPeriod = Math.min(
            swapOrder.lastPeriod,
            order.startingPeriod + order.numberOfSwaps - 1
        );
        amountToWithdraw = 0;
        for (
            uint256 period = order.lastPeriodWithdrawal + 1;
            period <= finalPeriod;
            period++
        ) {
            amountToWithdraw +=
                (swapOrder.swapExchangeRates[period] * order.amountPerSwap) /
                1e18;
        }
    }

    function calculateAmountWithdrawn(UserOrder memory order)
        public
        view
        returns (uint256 amountWithdrawn)
    {
        SwapOrder storage swapOrder = swapOrders[address(order.sellToken)][
            address(order.buyToken)
        ];

        amountWithdrawn = 0;
        for (
            uint256 period = order.startingPeriod;
            period <= order.lastPeriodWithdrawal;
            period++
        ) {
            amountWithdrawn +=
                (swapOrder.swapExchangeRates[period] * order.amountPerSwap) /
                1e18;
        }
    }

    function getUserOrders(address userAddress)
        external
        view
        returns (UserOrder[] memory)
    {
        return orders[userAddress];
    }

    function getUserOrdersWithExtras(address userAddress)
        external
        view
        returns (
            UserOrder[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256[] memory,
            uint256
        )
    {
        UserOrder[] memory userOrders = orders[userAddress];
        uint256[] memory ordersLastPeriod = new uint256[](userOrders.length);
        uint256[] memory amountsToWithdraw = new uint256[](userOrders.length);
        uint256[] memory amountsWithdrawn = new uint256[](userOrders.length);

        for (uint256 i = 0; i < userOrders.length; i++) {
            UserOrder memory order = userOrders[i];
            (
                uint256 amountToWithdraw,
                uint256 finalPeriod
            ) = calculateAmountToWithdraw(order);
            ordersLastPeriod[i] = finalPeriod;
            amountsToWithdraw[i] = amountToWithdraw;
            amountsWithdrawn[i] = calculateAmountWithdrawn(order);
        }

        return (
            userOrders,
            ordersLastPeriod,
            amountsToWithdraw,
            amountsWithdrawn,
            getCurrentPeriod()
        );
    }

    function getOrder(address userAddress, uint256 index)
        external
        view
        returns (UserOrder memory)
    {
        return orders[userAddress][index];
    }

    function getSwapOrderAmountToReduce(
        address _sellToken,
        address _buyToken,
        uint256 _period
    ) external view returns (uint256) {
        return swapOrders[_sellToken][_buyToken].amountsToReduce[_period];
    }

    function getSwapOrderExchangeRate(
        address _sellToken,
        address _buyToken,
        uint256 _period
    ) external view returns (uint256) {
        return swapOrders[_sellToken][_buyToken].swapExchangeRates[_period];
    }

    function getOracleTokenAddress(address token)
        public
        view
        returns (address)
    {
        address mappedToken = oracleAddresses[token];
        if (mappedToken != address(0)) {
            return mappedToken;
        } else {
            return token;
        }
    }

    function getCurrentPeriod() public view returns (uint256 period) {
        period = block.number / BLOCKS_PER_DAY;
    }
}
        

/_openzeppelin/contracts/access/Ownable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

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

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

/_openzeppelin/contracts/security/Pausable.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}
          

/_openzeppelin/contracts/token/ERC20/IERC20.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount
    ) external returns (bool);
}
          

/_openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

/_openzeppelin/contracts/utils/math/Math.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}
          

/contracts/interfaces/IOracle.sol

pragma solidity ^0.8.0;

interface Oracle {
    function consult(
        address tokenIn,
        uint256 amountIn,
        address tokenOut
    ) external view returns (uint256 amountOut);
}
          

/contracts/interfaces/ISwapper.sol

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface ISwapper {
    function swap(
        address _sellToken,
        address _buyToken,
        uint256 _inAmount,
        uint256 _outAmount,
        bytes calldata _params
    ) external;
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_oracle","internalType":"contract Oracle"},{"type":"address","name":"_beneficiary","internalType":"address"},{"type":"uint256","name":"initialFee","internalType":"uint256"}]},{"type":"event","name":"BeneficiarySet","inputs":[{"type":"address","name":"newBeneficiary","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"EmergencyWithdrawal","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"FeeNumeratorSet","inputs":[{"type":"uint256","name":"feeNumerator","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OracleAddressMappingSet","inputs":[{"type":"address","name":"from","internalType":"address","indexed":false},{"type":"address","name":"to","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OracleSet","inputs":[{"type":"address","name":"oracle","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OrderCreated","inputs":[{"type":"address","name":"userAddress","internalType":"address","indexed":true},{"type":"uint256","name":"index","internalType":"uint256","indexed":false},{"type":"address","name":"sellToken","internalType":"contract IERC20","indexed":true},{"type":"address","name":"buyToken","internalType":"contract IERC20","indexed":true},{"type":"uint256","name":"amountPerSwap","internalType":"uint256","indexed":false},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256","indexed":false},{"type":"uint256","name":"startingPeriod","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RemainingWithdrawal","inputs":[{"type":"address","name":"userAddress","internalType":"address","indexed":true},{"type":"uint256","name":"index","internalType":"uint256","indexed":true},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SwapExecuted","inputs":[{"type":"address","name":"sellToken","internalType":"address","indexed":true},{"type":"address","name":"buyToken","internalType":"address","indexed":true},{"type":"uint256","name":"sellAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"buyAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"period","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"SwappedWithdrawal","inputs":[{"type":"address","name":"userAddress","internalType":"address","indexed":true},{"type":"uint256","name":"index","internalType":"uint256","indexed":true},{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TokenPairInitialized","inputs":[{"type":"address","name":"sellToken","internalType":"address","indexed":false},{"type":"address","name":"buyToken","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BLOCKS_PER_DAY","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"FEE_DENOMINATOR","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_FEE_NUMERATOR","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addAddressMapping","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"address","name":"_to","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"beneficiary","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountToWithdraw","internalType":"uint256"},{"type":"uint256","name":"finalPeriod","internalType":"uint256"}],"name":"calculateAmountToWithdraw","inputs":[{"type":"tuple","name":"order","internalType":"struct DCA.UserOrder","components":[{"type":"address","name":"sellToken","internalType":"contract IERC20"},{"type":"address","name":"buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256"},{"type":"uint256","name":"startingPeriod","internalType":"uint256"},{"type":"uint256","name":"lastPeriodWithdrawal","internalType":"uint256"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountWithdrawn","internalType":"uint256"}],"name":"calculateAmountWithdrawn","inputs":[{"type":"tuple","name":"order","internalType":"struct DCA.UserOrder","components":[{"type":"address","name":"sellToken","internalType":"contract IERC20"},{"type":"address","name":"buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256"},{"type":"uint256","name":"startingPeriod","internalType":"uint256"},{"type":"uint256","name":"lastPeriodWithdrawal","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"index","internalType":"uint256"}],"name":"createOrder","inputs":[{"type":"address","name":"_sellToken","internalType":"contract IERC20"},{"type":"address","name":"_buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"_amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"_numberOfSwaps","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyWithdrawal","inputs":[{"type":"address","name":"token","internalType":"contract IERC20"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"executeOrder","inputs":[{"type":"address","name":"_sellToken","internalType":"address"},{"type":"address","name":"_buyToken","internalType":"address"},{"type":"uint256","name":"_period","internalType":"uint256"},{"type":"address","name":"_swapper","internalType":"address"},{"type":"bytes","name":"_params","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feeNumerator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"period","internalType":"uint256"}],"name":"getCurrentPeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getOracleTokenAddress","inputs":[{"type":"address","name":"token","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct DCA.UserOrder","components":[{"type":"address","name":"sellToken","internalType":"contract IERC20"},{"type":"address","name":"buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256"},{"type":"uint256","name":"startingPeriod","internalType":"uint256"},{"type":"uint256","name":"lastPeriodWithdrawal","internalType":"uint256"}]}],"name":"getOrder","inputs":[{"type":"address","name":"userAddress","internalType":"address"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSwapOrderAmountToReduce","inputs":[{"type":"address","name":"_sellToken","internalType":"address"},{"type":"address","name":"_buyToken","internalType":"address"},{"type":"uint256","name":"_period","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSwapOrderExchangeRate","inputs":[{"type":"address","name":"_sellToken","internalType":"address"},{"type":"address","name":"_buyToken","internalType":"address"},{"type":"uint256","name":"_period","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct DCA.UserOrder[]","components":[{"type":"address","name":"sellToken","internalType":"contract IERC20"},{"type":"address","name":"buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256"},{"type":"uint256","name":"startingPeriod","internalType":"uint256"},{"type":"uint256","name":"lastPeriodWithdrawal","internalType":"uint256"}]}],"name":"getUserOrders","inputs":[{"type":"address","name":"userAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct DCA.UserOrder[]","components":[{"type":"address","name":"sellToken","internalType":"contract IERC20"},{"type":"address","name":"buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256"},{"type":"uint256","name":"startingPeriod","internalType":"uint256"},{"type":"uint256","name":"lastPeriodWithdrawal","internalType":"uint256"}]},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"uint256[]","name":"","internalType":"uint256[]"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUserOrdersWithExtras","inputs":[{"type":"address","name":"userAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract Oracle"}],"name":"oracle","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"oracleAddresses","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"sellToken","internalType":"contract IERC20"},{"type":"address","name":"buyToken","internalType":"contract IERC20"},{"type":"uint256","name":"amountPerSwap","internalType":"uint256"},{"type":"uint256","name":"numberOfSwaps","internalType":"uint256"},{"type":"uint256","name":"startingPeriod","internalType":"uint256"},{"type":"uint256","name":"lastPeriodWithdrawal","internalType":"uint256"}],"name":"orders","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBeneficiary","inputs":[{"type":"address","name":"_beneficiary","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFeeNumerator","inputs":[{"type":"uint256","name":"_feeNumerator","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOracle","inputs":[{"type":"address","name":"_newOracle","internalType":"contract Oracle"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amountToSwap","internalType":"uint256"},{"type":"uint256","name":"lastPeriod","internalType":"uint256"}],"name":"swapOrders","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawAll","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawSwapped","inputs":[{"type":"uint256","name":"index","internalType":"uint256"}]}]
              

Contract Creation Code

0x6080346200008057601f62002e9e38819003918201601f19168301916001600160401b03831184841017620000855780849260609460405283398101031262000080578051620000709162000054826200009b565b604060208201519162000067836200009b565b015191620000ad565b604051612d059081620001998239f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116036200008057565b600080546001600160a01b03198082163390811784556040517fc1bcceddd77fdc95a8da9bec5802d2e0bb564dd02c0730222d8e12030bd910439760209790967f04d55a8be181fb8d75b76f2d48aa0b2ee40f47e53d6e61763eeeec46feea8a249689966001600160a01b039593947f3f32684a32a11dabdbb8c0177de80aa3ae36a004d75210335b49e544e48cd0aa948994919388938416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09086a316808760065416176006558152a11680916005541617600555604051908152a180600455604051908152a156fe60806040526004361015610013575b600080fd5b60003560e01c806306dc1f6a1461026b578063086146d2146102625780631b97e6e6146102595780631c31f710146102505780631d9dcf5114610247578063242b02d11461023e57806324b0b59c1461023557806337e5724b1461022c57806338af3eed146102235780633dea653b1461021a57806363c69f08146102115780636bb987fe14610208578063715018a6146101ff57806371eb125e146101f6578063793b8c6d146101ed5780637adbf973146101e45780637dc0d1d0146101db5780638da5cb5b146101d25780638ff9b843146101c9578063958e2d31146101c0578063a45db911146101b7578063aa24dca2146101ae578063d73792a9146101a5578063e111e3e71461019c578063e86dea4a14610193578063edb258411461018a578063f2c1063614610181578063f2fde38b14610178578063fd9b56871461016f5763fe8799181461016757600080fd5b61000e611870565b5061000e611834565b5061000e611740565b5061000e611717565b5061000e611667565b5061000e6115cf565b5061000e611594565b5061000e611557565b5061000e611362565b5061000e6112dc565b5061000e611012565b5061000e610f39565b5061000e610ee6565b5061000e610e93565b5061000e610ddb565b5061000e610d00565b5061000e610c3a565b5061000e610b92565b5061000e610b56565b5061000e610a9c565b5061000e610a16565b5061000e61097d565b5061000e610919565b5061000e6108a2565b5061000e61071a565b5061000e6105e8565b5061000e610530565b5061000e610503565b5061000e61044d565b5061000e61034f565b73ffffffffffffffffffffffffffffffffffffffff81160361000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60c0810190811067ffffffffffffffff8211176102de57604052565b6102e6610292565b604052565b67ffffffffffffffff81116102de57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176102de57604052565b6040519061034d826102c2565b565b503461000e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561038b81610274565b60243561039781610274565b6064356103a381610274565b6084359267ffffffffffffffff9283851161000e573660238601121561000e578460040135938411610435575b6040519361040660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601866102ff565b808552366024828801011161000e5760208160009260246104339901838901378601015260443591612308565b005b61043d610292565b6103d0565b600091031261000e57565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602060405161438043048152f35b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60c091011261000e576040516104c1816102c2565b6004356104cd81610274565b81526024356104db81610274565b602082015260443560408201526064356060820152608435608082015260a43560a082015290565b503461000e5761051a6105153661048b565b612a27565b60408051928352602083019190915290f35b0390f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577f04d55a8be181fb8d75b76f2d48aa0b2ee40f47e53d6e61763eeeec46feea8a24602060043561058f81610274565b73ffffffffffffffffffffffffffffffffffffffff906105b482600054163314611b8e565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555604051908152a1005b503461000e5760206106016105fc3661048b565b612b32565b604051908152f35b90815180825260208080930193019160005b828110610629575050505090565b909192938260c082610688600194895160a0809173ffffffffffffffffffffffffffffffffffffffff80825116855260208201511660208501526040810151604085015260608101516060850152608081015160808501520151910152565b0195019392910161061b565b90815180825260208080930193019160005b8281106106b4575050505090565b8351855293810193928101926001016106a6565b959493906080936106f9610715946106eb6107079460a08c5260a08c0190610609565b908a820360208c0152610694565b9088820360408a0152610694565b908682036060880152610694565b930152565b503461000e576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576004359061075882610274565b73ffffffffffffffffffffffffffffffffffffffff600092168252600281526040822080549061078782612c04565b9261079560405194856102ff565b82845280840191855280852085925b84841061083b5786866107b78151612c2b565b916107c28251612c2b565b926107cd8351612c2b565b915b8351811015610823578061080e6107e961081e9387612c7a565b516107f381612a27565b6107fd8588612c7a565b52610808848a612c7a565b52612b32565b6108188286612c7a565b526120dc565b6107cf565b509161052c91604051948594614380430493866106c8565b60068360019261084a85612817565b8152019201930192906107a4565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606091011261000e5760043561088e81610274565b9060243561089b81610274565b9060443590565b503461000e5773ffffffffffffffffffffffffffffffffffffffff60026109016108cb36610858565b94909116600052600160205260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b01906000526020526020604060002054604051908152f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602061095f60043561095a81610274565b612c9c565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc604091011261000e57600435610a0681610274565b90602435610a1381610274565b90565b503461000e57610a7173ffffffffffffffffffffffffffffffffffffffff610a3d366109d0565b9116600052600160205260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b805460019091015460408051928352602083019190915290f35b906020610a13928181520190610609565b503461000e576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5773ffffffffffffffffffffffffffffffffffffffff600435610aee81610274565b166000526002815260406000208054610b0681612c04565b91610b1460405193846102ff565b8183526000908152838120938084015b838310610b39576040518061052c8782610a8b565b600682600192610b4889612817565b815201960192019194610b24565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040516143808152f35b503461000e576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610c375780547fffffffffffffffffffffffff000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff821691610c09338414611b8e565b16825581604051917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08284a3f35b80fd5b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020600435610c7881610274565b73ffffffffffffffffffffffffffffffffffffffff8091166000526003825260406000205416604051908152f35b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8054821015610cf3575b6000526006602060002091020190600090565b610cfb610ca6565b610ce0565b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57600435610d3c81610274565b60243573ffffffffffffffffffffffffffffffffffffffff8092166000526002602052604060002090815481101561000e57610d7791610cd6565b50805460018201546002830154600384015460048501546005909501546040805173ffffffffffffffffffffffffffffffffffffffff96891687168152979094169094166020870152918501526060840152608083019190915260a082015260c090f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577f3f32684a32a11dabdbb8c0177de80aa3ae36a004d75210335b49e544e48cd0aa6020600435610e3a81610274565b73ffffffffffffffffffffffffffffffffffffffff90610e5f82600054163314611b8e565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b503461000e577f07d2c916c33b57e54689377381be3ef67a6a53c120daaf90e1e16f1645777e50610f69366109d0565b9073ffffffffffffffffffffffffffffffffffffffff610f8e81600054163314611b8e565b81166000526003602052610fe18260406000209073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152929091166020830152819081015b0390a1005b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561104e81612900565b6110818161107c3373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b610cd6565b50906111316110e96110c36110aa855473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b61110d6110aa600186015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b9161114d6111486004830154600384015490611e13565b611d94565b92600181018054851161115c57005b826111c86110aa926111c261126f95600273ffffffffffffffffffffffffffffffffffffffff98019061119182548254611dce565b81556111b76111af8c60038554940190600052602052604060002090565b918254611dce565b905554915489611dce565b90611cd9565b9560058201556112556000602061123b6111f96110aa865473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018c905293849283919082906044820190565b03925af19081156112cf575b6000916112a1575b50612875565b5473ffffffffffffffffffffffffffffffffffffffff1690565b604051938452169133907f1aea12ef3450ec7749a467b47e7d800a7b493e4601d440ac5aebb94f747c122890602090a4005b6112c2915060203d81116112c8575b6112ba81836102ff565b810190611d0a565b3861124f565b503d6112b0565b6112d7611d22565b611247565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577fc1bcceddd77fdc95a8da9bec5802d2e0bb564dd02c0730222d8e12030bd91043602060043561135573ffffffffffffffffffffffffffffffffffffffff600054163314611b8e565b80600455604051908152a1005b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577f3ab9db27a4cdd8c603a752b62d5fbd93b4b3509fe2596708e9688e42bbac35766004356113bf81610274565b602435906113cc82610274565b73ffffffffffffffffffffffffffffffffffffffff906113f182600054163314611b8e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529291169060208084602481865afa93841561154a575b600094611511575b506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024810185905261100d92916114af91818160448160008a5af1918215611504575b6000926114e7575b50506129c2565b6040519384938491939290604091606084019573ffffffffffffffffffffffffffffffffffffffff8093168552602085015216910152565b6114fd9250803d106112c8576112ba81836102ff565b38806114a8565b61150c611d22565b6114a0565b81945061153a6114af9161100d94933d8811611543575b61153281836102ff565b810190612068565b9491925061143b565b503d611528565b611552611d22565b611433565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020604051620f42408152f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57610433600435612900565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020600454604051908152f35b61034d9092919260c081019360a0809173ffffffffffffffffffffffffffffffffffffffff80825116855260208201511660208501526040810151604085015260608101516060850152608081015160808501520151910152565b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5761052c61170b61170560a073ffffffffffffffffffffffffffffffffffffffff6004356116c381610274565b6040516116cf816102c2565b60009381858093528260208201528260408201528260608201528260808201520152168152600260205260406024359120610cd6565b50612817565b6040519182918261160c565b503461000e5773ffffffffffffffffffffffffffffffffffffffff60036109016108cb36610858565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561177c81610274565b73ffffffffffffffffffffffffffffffffffffffff6117a081600054163314611b8e565b8116156117b05761043390611bf3565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040516117708152f35b503461000e5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5761052c6004356118af81610274565b6024356118bb81610274565b604435606435907faf8bd3c5abe498e30aea149b38afa6e7d9bbe58c9129b38eff2912440734c6e273ffffffffffffffffffffffffffffffffffffffff9384861693611972611955602061190f8488611cd9565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481019190915291829081906064820190565b038160008b5af1908115611b81575b600091611b63575b50611d2f565b611a6e6119cc6119a28773ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b97841680989073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b60018101805415611b06575b54611a2a6119e582611de5565b95611a0d6119f1610340565b73ffffffffffffffffffffffffffffffffffffffff909d168d52565b73ffffffffffffffffffffffffffffffffffffffff1660208c0152565b8660408b01528360608b01528460808b015260a08a0152611a4c868254611e13565b81556003611a5d6111488587611e13565b910190600052602052604060002090565b611a79858254611e13565b9055611ad9611aa83373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b5497611ad43373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b611e1f565b60408051888152602081019590955284015260608301523391608090a46040519081529081906020820190565b611b136143804304611d94565b81556040805173ffffffffffffffffffffffffffffffffffffffff8a811682528b1660208201527f1860ddfae81fa4edaec7accf480512d07263c8e909d5cdae84da78e098fc7b099190a16119d8565b611b7b915060203d81116112c8576112ba81836102ff565b3861196c565b611b89611d22565b611964565b15611b9557565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6000549073ffffffffffffffffffffffffffffffffffffffff80911691827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e06000604051a3565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b670de0b6b3a764000090807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821181151516611ccd570290565b611cd5611c62565b0290565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821181151516611ccd570290565b9081602091031261000e5751801515810361000e5790565b506040513d6000823e3d90fd5b15611d3657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4443413a204e6f7420656e6f7567682066756e647300000000000000000000006044820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060018110611dc2570190565b611dca611c62565b0190565b818110611dd9570390565b611de1611c62565b0390565b6001907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8111611dc2570190565b81198111611dc2570190565b8054611e429168010000000000000000821015611f32575b600182018155610cd6565b919091611f0357805182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91821617835560059160a091611ede90602083015116600186019073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6040810151600285015560608101516003850155608081015160048501550151910155565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b611f3a610292565b611e37565b15611f4657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4443413a20496e76616c696420706572696f64000000000000000000000000006044820152fd5b15611fab57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f4443413a20506572696f642063616e6e6f7420626520696e207468652066757460448201527f75726500000000000000000000000000000000000000000000000000000000006064820152fd5b8115612039570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b9081602091031261000e575190565b1561207e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4443413a204f7261636c65206661696c757265000000000000000000000000006044820152fd5b6001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611dc2570190565b1561211157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4443413a20466565207472616e7366657220746f2062656e656669636961727960448201527f206661696c6564000000000000000000000000000000000000000000000000006064820152fd5b1561219c57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4443413a205472616e7366657220746f2053776170706572206661696c6564006044820152fd5b9391929095949573ffffffffffffffffffffffffffffffffffffffff809116855260209316838501526040840152606083015260a060808301528351908160a08401526000945b82861061228d575050601f817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09260c0959611612280575b0116010190565b6000858286010152612279565b85810182015184870160c0015294810194612241565b156122aa57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4443413a204e6f7420656e6f7567682062616c616e63652072657475726e65646044820152fd5b9261244e909492946123638361233e8773ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b9073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b9360018501549161237d8861237785611de5565b14611f3f565b61238d6143804304891115611fa4565b8554956123b26123ab6123a26004548a611cd9565b620f4240900490565b8098611dce565b9360206123d76110aa60065473ffffffffffffffffffffffffffffffffffffffff1690565b6123e08b612c9c565b90876123eb8b612c9c565b926040519a8b94859384937f8c86f1e40000000000000000000000000000000000000000000000000000000085526004850191939290604091606084019573ffffffffffffffffffffffffffffffffffffffff8093168552602085015216910152565b03915afa95861561280a575b6000966127e5575b5061247790612472871515612077565b6120dc565b600182015561248e8461248987611c92565b61202f565b60008a81526002830160205260409020556124c16124b98a6003840190600052602052604060002090565b548254611dce565b905573ffffffffffffffffffffffffffffffffffffffff968781169661257c600060206125628b61250760055473ffffffffffffffffffffffffffffffffffffffff1690565b956040519485809481937fa9059cbb000000000000000000000000000000000000000000000000000000009a8b8452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af19081156127d8575b6000916127b9575b5061210a565b6040517f70a0823100000000000000000000000000000000000000000000000000000000808252306004830152888b169a9094919290919087908b906020868f81806024810103915afa9586156127ac575b60009661277e575b5060405190815273ffffffffffffffffffffffffffffffffffffffff84166004820152602481019290925261262e9190602090829081600081604481015b03925af1908115612771575b600091612752575b50612195565b1690813b1561000e578660008782947f28c738dbec11a1bed94ba127a3712d54bcd39cf4ae95b6ebd671aaf10fd0287b9b836126b7986126a16126e49c604051988997889687957f2506c018000000000000000000000000000000000000000000000000000000008752600487016121fa565b03925af18015612745575b61272c575b50611e13565b6040519182523060048301526020826024818b5afa91821561271f575b6000926126fe575b5011156122a3565b60408051918252602082019290925290819081015b0390a4565b61271891925060203d6020116115435761153281836102ff565b90386126dc565b612727611d22565b6126d4565b8061273961273f926102eb565b80610442565b386126b1565b61274d611d22565b6126ac565b61276b915060203d6020116112c8576112ba81836102ff565b38612628565b612779611d22565b612620565b602091965092612614926127a161262e95843d86116115435761153281836102ff565b9792509250926125d6565b6127b4611d22565b6125ce565b6127d2915060203d6020116112c8576112ba81836102ff565b38612576565b6127e0611d22565b61256e565b6124779196506128039060203d6020116115435761153281836102ff565b9590612462565b612812611d22565b61245a565b90604051612824816102c2565b60a06005829473ffffffffffffffffffffffffffffffffffffffff80825416855260018201541660208501526002810154604085015260038101546060850152600481015460808501520154910152565b1561287c57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4443413a204e6f7420656e6f7567682066756e647320746f207769746864726160448201527f77000000000000000000000000000000000000000000000000000000000000006064820152fd5b61292e8161107c3373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b509073ffffffffffffffffffffffffffffffffffffffff61298c6110aa600161295961051587612817565b60058892980155016112556000602061123b6111f96110aa865473ffffffffffffffffffffffffffffffffffffffff1690565b604051938452169133907fe6f9d2780c8923607fbb084350c15a1655c3fc682c989303c218a016a00324a09080602081016126f9565b156129c957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4443413a20456d657267656e6379207472616e73666572206661696c656400006044820152fd5b90612a86612a626110c373ffffffffffffffffffffffffffffffffffffffff85511673ffffffffffffffffffffffffffffffffffffffff1690565b61110d6110aa602086015173ffffffffffffffffffffffffffffffffffffffff1690565b90612aab6001830154612aa56111486080870151606088015190611e13565b90612b20565b916000936002612abe60a0830151611de5565b9201905b84831115612acf57505050565b909194612b13612b1991612b0d612aff612af38a8890600052602052604060002090565b54604087015190611cd9565b670de0b6b3a7640000900490565b90611e13565b956120dc565b9190612ac2565b9080821015612b2d575090565b905090565b9073ffffffffffffffffffffffffffffffffffffffff9182815116906000918252600190602094828652612b8f60409182862090888501511673ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b93838197600260808601519701915b612bac575b50505050505050565b9091929394959760a08601518911612bfe57612bec612bf2918a8652848452670de0b6b3a7640000612be588882054898b015190611cd9565b0490611e13565b986120dc565b95949392919085612b9e565b97612ba3565b60209067ffffffffffffffff8111612c1e575b60051b0190565b612c26610292565b612c17565b90612c3582612c04565b612c4260405191826102ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612c708294612c04565b0190602036910137565b6020918151811015612c8f575b60051b010190565b612c97610ca6565b612c87565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526003602052604090205416908115612b2d57509056fea264697066735822122081edebb9763b8669ddd759daafae5740cd30459d6d949c9d156495105dd23c7164736f6c634300080d0033000000000000000000000000056d9aac902cc2925bb31f6c516b1e1579c35df9000000000000000000000000aca6fbe30f1557004d261e2d905b82571ac9bab70000000000000000000000000000000000000000000000000000000000000fa0

Deployed ByteCode

0x60806040526004361015610013575b600080fd5b60003560e01c806306dc1f6a1461026b578063086146d2146102625780631b97e6e6146102595780631c31f710146102505780631d9dcf5114610247578063242b02d11461023e57806324b0b59c1461023557806337e5724b1461022c57806338af3eed146102235780633dea653b1461021a57806363c69f08146102115780636bb987fe14610208578063715018a6146101ff57806371eb125e146101f6578063793b8c6d146101ed5780637adbf973146101e45780637dc0d1d0146101db5780638da5cb5b146101d25780638ff9b843146101c9578063958e2d31146101c0578063a45db911146101b7578063aa24dca2146101ae578063d73792a9146101a5578063e111e3e71461019c578063e86dea4a14610193578063edb258411461018a578063f2c1063614610181578063f2fde38b14610178578063fd9b56871461016f5763fe8799181461016757600080fd5b61000e611870565b5061000e611834565b5061000e611740565b5061000e611717565b5061000e611667565b5061000e6115cf565b5061000e611594565b5061000e611557565b5061000e611362565b5061000e6112dc565b5061000e611012565b5061000e610f39565b5061000e610ee6565b5061000e610e93565b5061000e610ddb565b5061000e610d00565b5061000e610c3a565b5061000e610b92565b5061000e610b56565b5061000e610a9c565b5061000e610a16565b5061000e61097d565b5061000e610919565b5061000e6108a2565b5061000e61071a565b5061000e6105e8565b5061000e610530565b5061000e610503565b5061000e61044d565b5061000e61034f565b73ffffffffffffffffffffffffffffffffffffffff81160361000e57565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60c0810190811067ffffffffffffffff8211176102de57604052565b6102e6610292565b604052565b67ffffffffffffffff81116102de57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176102de57604052565b6040519061034d826102c2565b565b503461000e5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561038b81610274565b60243561039781610274565b6064356103a381610274565b6084359267ffffffffffffffff9283851161000e573660238601121561000e578460040135938411610435575b6040519361040660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601866102ff565b808552366024828801011161000e5760208160009260246104339901838901378601015260443591612308565b005b61043d610292565b6103d0565b600091031261000e57565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602060405161438043048152f35b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60c091011261000e576040516104c1816102c2565b6004356104cd81610274565b81526024356104db81610274565b602082015260443560408201526064356060820152608435608082015260a43560a082015290565b503461000e5761051a6105153661048b565b612a27565b60408051928352602083019190915290f35b0390f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577f04d55a8be181fb8d75b76f2d48aa0b2ee40f47e53d6e61763eeeec46feea8a24602060043561058f81610274565b73ffffffffffffffffffffffffffffffffffffffff906105b482600054163314611b8e565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006005541617600555604051908152a1005b503461000e5760206106016105fc3661048b565b612b32565b604051908152f35b90815180825260208080930193019160005b828110610629575050505090565b909192938260c082610688600194895160a0809173ffffffffffffffffffffffffffffffffffffffff80825116855260208201511660208501526040810151604085015260608101516060850152608081015160808501520151910152565b0195019392910161061b565b90815180825260208080930193019160005b8281106106b4575050505090565b8351855293810193928101926001016106a6565b959493906080936106f9610715946106eb6107079460a08c5260a08c0190610609565b908a820360208c0152610694565b9088820360408a0152610694565b908682036060880152610694565b930152565b503461000e576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576004359061075882610274565b73ffffffffffffffffffffffffffffffffffffffff600092168252600281526040822080549061078782612c04565b9261079560405194856102ff565b82845280840191855280852085925b84841061083b5786866107b78151612c2b565b916107c28251612c2b565b926107cd8351612c2b565b915b8351811015610823578061080e6107e961081e9387612c7a565b516107f381612a27565b6107fd8588612c7a565b52610808848a612c7a565b52612b32565b6108188286612c7a565b526120dc565b6107cf565b509161052c91604051948594614380430493866106c8565b60068360019261084a85612817565b8152019201930192906107a4565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc606091011261000e5760043561088e81610274565b9060243561089b81610274565b9060443590565b503461000e5773ffffffffffffffffffffffffffffffffffffffff60026109016108cb36610858565b94909116600052600160205260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b01906000526020526020604060002054604051908152f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602061095f60043561095a81610274565b612c9c565b73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60055416604051908152f35b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc604091011261000e57600435610a0681610274565b90602435610a1381610274565b90565b503461000e57610a7173ffffffffffffffffffffffffffffffffffffffff610a3d366109d0565b9116600052600160205260406000209073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b805460019091015460408051928352602083019190915290f35b906020610a13928181520190610609565b503461000e576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5773ffffffffffffffffffffffffffffffffffffffff600435610aee81610274565b166000526002815260406000208054610b0681612c04565b91610b1460405193846102ff565b8183526000908152838120938084015b838310610b39576040518061052c8782610a8b565b600682600192610b4889612817565b815201960192019194610b24565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040516143808152f35b503461000e576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610c375780547fffffffffffffffffffffffff000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff821691610c09338414611b8e565b16825581604051917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08284a3f35b80fd5b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020600435610c7881610274565b73ffffffffffffffffffffffffffffffffffffffff8091166000526003825260406000205416604051908152f35b507f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8054821015610cf3575b6000526006602060002091020190600090565b610cfb610ca6565b610ce0565b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57600435610d3c81610274565b60243573ffffffffffffffffffffffffffffffffffffffff8092166000526002602052604060002090815481101561000e57610d7791610cd6565b50805460018201546002830154600384015460048501546005909501546040805173ffffffffffffffffffffffffffffffffffffffff96891687168152979094169094166020870152918501526060840152608083019190915260a082015260c090f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577f3f32684a32a11dabdbb8c0177de80aa3ae36a004d75210335b49e544e48cd0aa6020600435610e3a81610274565b73ffffffffffffffffffffffffffffffffffffffff90610e5f82600054163314611b8e565b16807fffffffffffffffffffffffff00000000000000000000000000000000000000006006541617600655604051908152a1005b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60065416604051908152f35b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b503461000e577f07d2c916c33b57e54689377381be3ef67a6a53c120daaf90e1e16f1645777e50610f69366109d0565b9073ffffffffffffffffffffffffffffffffffffffff610f8e81600054163314611b8e565b81166000526003602052610fe18260406000209073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152929091166020830152819081015b0390a1005b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561104e81612900565b6110818161107c3373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b610cd6565b50906111316110e96110c36110aa855473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b61110d6110aa600186015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b9161114d6111486004830154600384015490611e13565b611d94565b92600181018054851161115c57005b826111c86110aa926111c261126f95600273ffffffffffffffffffffffffffffffffffffffff98019061119182548254611dce565b81556111b76111af8c60038554940190600052602052604060002090565b918254611dce565b905554915489611dce565b90611cd9565b9560058201556112556000602061123b6111f96110aa865473ffffffffffffffffffffffffffffffffffffffff1690565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018c905293849283919082906044820190565b03925af19081156112cf575b6000916112a1575b50612875565b5473ffffffffffffffffffffffffffffffffffffffff1690565b604051938452169133907f1aea12ef3450ec7749a467b47e7d800a7b493e4601d440ac5aebb94f747c122890602090a4005b6112c2915060203d81116112c8575b6112ba81836102ff565b810190611d0a565b3861124f565b503d6112b0565b6112d7611d22565b611247565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577fc1bcceddd77fdc95a8da9bec5802d2e0bb564dd02c0730222d8e12030bd91043602060043561135573ffffffffffffffffffffffffffffffffffffffff600054163314611b8e565b80600455604051908152a1005b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e577f3ab9db27a4cdd8c603a752b62d5fbd93b4b3509fe2596708e9688e42bbac35766004356113bf81610274565b602435906113cc82610274565b73ffffffffffffffffffffffffffffffffffffffff906113f182600054163314611b8e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201529291169060208084602481865afa93841561154a575b600094611511575b506040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024810185905261100d92916114af91818160448160008a5af1918215611504575b6000926114e7575b50506129c2565b6040519384938491939290604091606084019573ffffffffffffffffffffffffffffffffffffffff8093168552602085015216910152565b6114fd9250803d106112c8576112ba81836102ff565b38806114a8565b61150c611d22565b6114a0565b81945061153a6114af9161100d94933d8811611543575b61153281836102ff565b810190612068565b9491925061143b565b503d611528565b611552611d22565b611433565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020604051620f42408152f35b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e57610433600435612900565b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e576020600454604051908152f35b61034d9092919260c081019360a0809173ffffffffffffffffffffffffffffffffffffffff80825116855260208201511660208501526040810151604085015260608101516060850152608081015160808501520151910152565b503461000e5760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5761052c61170b61170560a073ffffffffffffffffffffffffffffffffffffffff6004356116c381610274565b6040516116cf816102c2565b60009381858093528260208201528260408201528260608201528260808201520152168152600260205260406024359120610cd6565b50612817565b6040519182918261160c565b503461000e5773ffffffffffffffffffffffffffffffffffffffff60036109016108cb36610858565b503461000e5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760043561177c81610274565b73ffffffffffffffffffffffffffffffffffffffff6117a081600054163314611b8e565b8116156117b05761043390611bf3565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b503461000e5760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5760206040516117708152f35b503461000e5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261000e5761052c6004356118af81610274565b6024356118bb81610274565b604435606435907faf8bd3c5abe498e30aea149b38afa6e7d9bbe58c9129b38eff2912440734c6e273ffffffffffffffffffffffffffffffffffffffff9384861693611972611955602061190f8488611cd9565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481019190915291829081906064820190565b038160008b5af1908115611b81575b600091611b63575b50611d2f565b611a6e6119cc6119a28773ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b97841680989073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b60018101805415611b06575b54611a2a6119e582611de5565b95611a0d6119f1610340565b73ffffffffffffffffffffffffffffffffffffffff909d168d52565b73ffffffffffffffffffffffffffffffffffffffff1660208c0152565b8660408b01528360608b01528460808b015260a08a0152611a4c868254611e13565b81556003611a5d6111488587611e13565b910190600052602052604060002090565b611a79858254611e13565b9055611ad9611aa83373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b5497611ad43373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b611e1f565b60408051888152602081019590955284015260608301523391608090a46040519081529081906020820190565b611b136143804304611d94565b81556040805173ffffffffffffffffffffffffffffffffffffffff8a811682528b1660208201527f1860ddfae81fa4edaec7accf480512d07263c8e909d5cdae84da78e098fc7b099190a16119d8565b611b7b915060203d81116112c8576112ba81836102ff565b3861196c565b611b89611d22565b611964565b15611b9557565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b6000549073ffffffffffffffffffffffffffffffffffffffff80911691827fffffffffffffffffffffffff0000000000000000000000000000000000000000821617600055167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e06000604051a3565b507f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b670de0b6b3a764000090807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821181151516611ccd570290565b611cd5611c62565b0290565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821181151516611ccd570290565b9081602091031261000e5751801515810361000e5790565b506040513d6000823e3d90fd5b15611d3657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4443413a204e6f7420656e6f7567682066756e647300000000000000000000006044820152fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060018110611dc2570190565b611dca611c62565b0190565b818110611dd9570390565b611de1611c62565b0390565b6001907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8111611dc2570190565b81198111611dc2570190565b8054611e429168010000000000000000821015611f32575b600182018155610cd6565b919091611f0357805182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91821617835560059160a091611ede90602083015116600186019073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055565b6040810151600285015560608101516003850155608081015160048501550151910155565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600060045260246000fd5b611f3a610292565b611e37565b15611f4657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4443413a20496e76616c696420706572696f64000000000000000000000000006044820152fd5b15611fab57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f4443413a20506572696f642063616e6e6f7420626520696e207468652066757460448201527f75726500000000000000000000000000000000000000000000000000000000006064820152fd5b8115612039570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b9081602091031261000e575190565b1561207e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4443413a204f7261636c65206661696c757265000000000000000000000000006044820152fd5b6001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611dc2570190565b1561211157565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f4443413a20466565207472616e7366657220746f2062656e656669636961727960448201527f206661696c6564000000000000000000000000000000000000000000000000006064820152fd5b1561219c57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4443413a205472616e7366657220746f2053776170706572206661696c6564006044820152fd5b9391929095949573ffffffffffffffffffffffffffffffffffffffff809116855260209316838501526040840152606083015260a060808301528351908160a08401526000945b82861061228d575050601f817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09260c0959611612280575b0116010190565b6000858286010152612279565b85810182015184870160c0015294810194612241565b156122aa57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4443413a204e6f7420656e6f7567682062616c616e63652072657475726e65646044820152fd5b9261244e909492946123638361233e8773ffffffffffffffffffffffffffffffffffffffff166000526001602052604060002090565b9073ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b9360018501549161237d8861237785611de5565b14611f3f565b61238d6143804304891115611fa4565b8554956123b26123ab6123a26004548a611cd9565b620f4240900490565b8098611dce565b9360206123d76110aa60065473ffffffffffffffffffffffffffffffffffffffff1690565b6123e08b612c9c565b90876123eb8b612c9c565b926040519a8b94859384937f8c86f1e40000000000000000000000000000000000000000000000000000000085526004850191939290604091606084019573ffffffffffffffffffffffffffffffffffffffff8093168552602085015216910152565b03915afa95861561280a575b6000966127e5575b5061247790612472871515612077565b6120dc565b600182015561248e8461248987611c92565b61202f565b60008a81526002830160205260409020556124c16124b98a6003840190600052602052604060002090565b548254611dce565b905573ffffffffffffffffffffffffffffffffffffffff968781169661257c600060206125628b61250760055473ffffffffffffffffffffffffffffffffffffffff1690565b956040519485809481937fa9059cbb000000000000000000000000000000000000000000000000000000009a8b8452600484016020909392919373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af19081156127d8575b6000916127b9575b5061210a565b6040517f70a0823100000000000000000000000000000000000000000000000000000000808252306004830152888b169a9094919290919087908b906020868f81806024810103915afa9586156127ac575b60009661277e575b5060405190815273ffffffffffffffffffffffffffffffffffffffff84166004820152602481019290925261262e9190602090829081600081604481015b03925af1908115612771575b600091612752575b50612195565b1690813b1561000e578660008782947f28c738dbec11a1bed94ba127a3712d54bcd39cf4ae95b6ebd671aaf10fd0287b9b836126b7986126a16126e49c604051988997889687957f2506c018000000000000000000000000000000000000000000000000000000008752600487016121fa565b03925af18015612745575b61272c575b50611e13565b6040519182523060048301526020826024818b5afa91821561271f575b6000926126fe575b5011156122a3565b60408051918252602082019290925290819081015b0390a4565b61271891925060203d6020116115435761153281836102ff565b90386126dc565b612727611d22565b6126d4565b8061273961273f926102eb565b80610442565b386126b1565b61274d611d22565b6126ac565b61276b915060203d6020116112c8576112ba81836102ff565b38612628565b612779611d22565b612620565b602091965092612614926127a161262e95843d86116115435761153281836102ff565b9792509250926125d6565b6127b4611d22565b6125ce565b6127d2915060203d6020116112c8576112ba81836102ff565b38612576565b6127e0611d22565b61256e565b6124779196506128039060203d6020116115435761153281836102ff565b9590612462565b612812611d22565b61245a565b90604051612824816102c2565b60a06005829473ffffffffffffffffffffffffffffffffffffffff80825416855260018201541660208501526002810154604085015260038101546060850152600481015460808501520154910152565b1561287c57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f4443413a204e6f7420656e6f7567682066756e647320746f207769746864726160448201527f77000000000000000000000000000000000000000000000000000000000000006064820152fd5b61292e8161107c3373ffffffffffffffffffffffffffffffffffffffff166000526002602052604060002090565b509073ffffffffffffffffffffffffffffffffffffffff61298c6110aa600161295961051587612817565b60058892980155016112556000602061123b6111f96110aa865473ffffffffffffffffffffffffffffffffffffffff1690565b604051938452169133907fe6f9d2780c8923607fbb084350c15a1655c3fc682c989303c218a016a00324a09080602081016126f9565b156129c957565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f4443413a20456d657267656e6379207472616e73666572206661696c656400006044820152fd5b90612a86612a626110c373ffffffffffffffffffffffffffffffffffffffff85511673ffffffffffffffffffffffffffffffffffffffff1690565b61110d6110aa602086015173ffffffffffffffffffffffffffffffffffffffff1690565b90612aab6001830154612aa56111486080870151606088015190611e13565b90612b20565b916000936002612abe60a0830151611de5565b9201905b84831115612acf57505050565b909194612b13612b1991612b0d612aff612af38a8890600052602052604060002090565b54604087015190611cd9565b670de0b6b3a7640000900490565b90611e13565b956120dc565b9190612ac2565b9080821015612b2d575090565b905090565b9073ffffffffffffffffffffffffffffffffffffffff9182815116906000918252600190602094828652612b8f60409182862090888501511673ffffffffffffffffffffffffffffffffffffffff16600052602052604060002090565b93838197600260808601519701915b612bac575b50505050505050565b9091929394959760a08601518911612bfe57612bec612bf2918a8652848452670de0b6b3a7640000612be588882054898b015190611cd9565b0490611e13565b986120dc565b95949392919085612b9e565b97612ba3565b60209067ffffffffffffffff8111612c1e575b60051b0190565b612c26610292565b612c17565b90612c3582612c04565b612c4260405191826102ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0612c708294612c04565b0190602036910137565b6020918151811015612c8f575b60051b010190565b612c97610ca6565b612c87565b73ffffffffffffffffffffffffffffffffffffffff81811660009081526003602052604090205416908115612b2d57509056fea264697066735822122081edebb9763b8669ddd759daafae5740cd30459d6d949c9d156495105dd23c7164736f6c634300080d0033