Contract Address Details

0x9834C515346CD8e62249e19bf32Ce37eE3267575

Contract Name
Bridge
Creator
0x9a0313–3d9e42 at 0x340f44–66d1bb
Balance
0 mADA
Tokens
Fetching tokens...
Transactions
8 Transactions
Transfers
4 Transfers
Gas Used
1,045,115
Last Balance Update
44819178
Contract name:
Bridge




Optimization enabled
false
Compiler version
v0.8.6+commit.11564f7e




Verified at
2022-10-04T17:22:28.650889Z

Constructor Arguments

000000000000000000000000c2eb9e06602d5e043905127a8f4f2e3a6bc057e7

Arg [0] (address) : 0xc2eb9e06602d5e043905127a8f4f2e3a6bc057e7

              

contracts/Bridge.sol

// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.6;

// OpenZeppelin
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

interface IBridgeMigrationSource {
    function tokenAddress() external view returns (address);
    function settlingAgent() external view returns (address payable);
}

contract Bridge is Ownable {

    using SafeMath for uint256;

    struct BridgeRequest {
        address account;
        uint256 amount;
        uint256 blockNumber;
        uint256 timestamp;
    }

    event RequestSent (uint256 indexed _id, address indexed _account, uint256 _amount, uint256 _blocknumber);
    event RequestReceived (uint256 indexed _id, address indexed _account, uint256 _amount, uint256 _amountPaid, uint256 _blocknumber);

    event RequiredConfirmationsChanged (uint256 _value);
    event PayoutRatioChanged (uint256 _nominator, uint256 _denominator);

    constructor(address _tokenAddress) {
        settlingAgent = payable(msg.sender);
        tokenAddress = _tokenAddress;
    }

    address payable public settlingAgent;
    function setSettlingAgent(address _address) public onlyOwner {
        settlingAgent = payable(_address);
    }

    address public tokenAddress;
    function setTokenAddress(address _address) public onlyOwner {
        tokenAddress = _address;
    }

    uint256 public payoutRatioNominator = 1;
    uint256 public payoutRatioDenominator = 1;
    function setPayoutRatio(uint256 _nominator, uint256 _denominator) public onlyOwner {
        require(_nominator > 0, "Nominator must be greater than zero");
        require(_denominator > 0, "Denominator must be greater than zero");

        payoutRatioNominator = _nominator;
        payoutRatioDenominator = _denominator;

        emit PayoutRatioChanged(_nominator, _denominator);
    }

    uint256 public outgoingTransferFee = 0.1 * 10**18;
    function setOutgoingTransferFee(uint256 _amount) public onlyOwner {
        outgoingTransferFee = _amount;
    }

    uint256 public maximumTransferAmount = 0;
    function setMaximumTransferAmount(uint256 _amount) public onlyOwner {
        maximumTransferAmount = _amount;
    }

    uint256 public requiredConfirmations = 20;
    function setRequiredConfirmations(uint256 _amount) public onlyOwner {
        requiredConfirmations = _amount;
        emit RequiredConfirmationsChanged(_amount);
    }

    modifier onlyAgent() {
        require(msg.sender == settlingAgent, "This action can only be executed by the settling agent");
        _;
    }

    uint256 public sentRequestCount;
    mapping (uint256 => BridgeRequest) public sentRequests;

    uint256 public receivedRequestCount;
    mapping (uint256 => bool) public receivedRequests;

    function withdrawETH() public onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }
    function withdrawToken(address _tokenAddress) public onlyOwner {
        IERC20 token = IERC20(_tokenAddress);
        require(token.transfer(owner(), token.balanceOf(address(this))), "Failed to transfer tokens");
    }

    function bridgeToken(uint256 _amount) public payable  {
        require(msg.value >= outgoingTransferFee, "Underpaid transaction: please provide the outgoing transfer fee." );
        require(_amount <= maximumTransferAmount || maximumTransferAmount == 0, "Requested amount exceeds maximum amount to transfer.");

        IERC20 erc20 = IERC20(tokenAddress);

        uint256 balanceBefore = erc20.balanceOf(address(this));
        require(erc20.transferFrom (msg.sender, address(this) , _amount), "Transferring tokens was cancelled by the token contract. Please check with the token developer.");

        uint256 balanceExpected = balanceBefore + _amount;
        require(erc20.balanceOf(address(this)) >= balanceExpected, "Did not receive enough tokens from sender. Is the bridge exempted from taxes?");

        sentRequestCount++;
        settlingAgent.transfer(msg.value);

        sentRequests[sentRequestCount].account =  msg.sender;
        sentRequests[sentRequestCount].amount = _amount;
        sentRequests[sentRequestCount].blockNumber = block.number;
        sentRequests[sentRequestCount].timestamp = block.timestamp;

        emit RequestSent(sentRequestCount, msg.sender, _amount, block.number);
    }
    function settleRequest(uint256 _id, address _account, uint256 _amount) public onlyAgent {

        IERC20 erc20 = IERC20(tokenAddress);
        uint256 _amountRespectingPayoutRatio = _amount.mul(payoutRatioNominator).div(payoutRatioDenominator);

        require (!receivedRequests[_id], "This request was already settled");
        require (erc20.balanceOf(address(this)) >= _amountRespectingPayoutRatio, "Token deposit insufficient for settlement");

        receivedRequestCount++;
        receivedRequests[receivedRequestCount] = true;

        require(erc20.transfer(_account, _amountRespectingPayoutRatio), "Failed to send tokens to the receiving account.");

        emit RequestReceived(receivedRequestCount, _account, _amount, _amountRespectingPayoutRatio, block.number);
    }

    receive() external payable {}
    fallback() external payable {}

    function migrateFrom(address _oldAddress) public onlyOwner {
        IBridgeMigrationSource oldBridge = IBridgeMigrationSource(_oldAddress);

        tokenAddress = oldBridge.tokenAddress();
        settlingAgent = oldBridge.settlingAgent();

        payoutRatioNominator = tryGetValue(_oldAddress, "payoutRatioNominator()", payoutRatioNominator);
        payoutRatioDenominator = tryGetValue(_oldAddress, "payoutRatioDenominator()", payoutRatioDenominator);
        outgoingTransferFee = tryGetValue(_oldAddress, "outgoingTransferFee()", outgoingTransferFee);
        maximumTransferAmount = tryGetValue(_oldAddress, "maximumTransferAmount()", maximumTransferAmount);
        requiredConfirmations = tryGetValue(_oldAddress, "requiredConfirmations()", requiredConfirmations);
    }
    function tryGetValue(address _address, string memory _signature, uint256 _fallback) private view returns (uint256) {
        (bool result, bytes memory retval) = _address.staticcall(abi.encodeWithSignature(_signature));
        if (result) {
            return abi.decode(retval, (uint256));
        }
        else {
            return _fallback;
        }
    }
}
        

@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/token/ERC20/IERC20.sol

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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);
}
          

@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/SafeMath.sol

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

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"}]},{"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":"PayoutRatioChanged","inputs":[{"type":"uint256","name":"_nominator","internalType":"uint256","indexed":false},{"type":"uint256","name":"_denominator","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RequestReceived","inputs":[{"type":"uint256","name":"_id","internalType":"uint256","indexed":true},{"type":"address","name":"_account","internalType":"address","indexed":true},{"type":"uint256","name":"_amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_amountPaid","internalType":"uint256","indexed":false},{"type":"uint256","name":"_blocknumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RequestSent","inputs":[{"type":"uint256","name":"_id","internalType":"uint256","indexed":true},{"type":"address","name":"_account","internalType":"address","indexed":true},{"type":"uint256","name":"_amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_blocknumber","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RequiredConfirmationsChanged","inputs":[{"type":"uint256","name":"_value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"fallback","stateMutability":"payable"},{"type":"function","stateMutability":"payable","outputs":[],"name":"bridgeToken","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"maximumTransferAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"migrateFrom","inputs":[{"type":"address","name":"_oldAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"outgoingTransferFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"payoutRatioDenominator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"payoutRatioNominator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"receivedRequestCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"receivedRequests","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"requiredConfirmations","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"sentRequestCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"blockNumber","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"sentRequests","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaximumTransferAmount","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOutgoingTransferFee","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPayoutRatio","inputs":[{"type":"uint256","name":"_nominator","internalType":"uint256"},{"type":"uint256","name":"_denominator","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequiredConfirmations","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSettlingAgent","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTokenAddress","inputs":[{"type":"address","name":"_address","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"settleRequest","inputs":[{"type":"uint256","name":"_id","internalType":"uint256"},{"type":"address","name":"_account","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address payable"}],"name":"settlingAgent","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tokenAddress","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawETH","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawToken","inputs":[{"type":"address","name":"_tokenAddress","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
            

Deployed ByteCode

0x6080604052600436106101695760003560e01c806389476069116100d1578063ca9b294d1161008a578063df12d57811610064578063df12d578146104d6578063e086e5ec14610516578063e9b9cf421461052d578063f2fde38b1461055857610170565b8063ca9b294d14610466578063db9ce31614610491578063dbb5868d146104ba57610170565b806389476069146103685780638da5cb5b1461039157806391321a81146103bc5780639d76ea58146103e5578063bc24ca3a14610410578063c424dad81461043b57610170565b80635a6f96ae116101235780635a6f96ae1461027e57806361beb823146102a957806367aaf555146102d4578063715018a6146102fd5780637b7c343d1461031457806382e717f71461033d57610170565b80620f71171461017257806326a4e8d2146101af5780632ae01f3f146101d857806333c8a6731461020157806335657e681461022a5780635865d2ae1461025357610170565b3661017057005b005b34801561017e57600080fd5b5061019960048036038101906101949190611df6565b610581565b6040516101a69190612251565b60405180910390f35b3480156101bb57600080fd5b506101d660048036038101906101d19190611d42565b6105a1565b005b3480156101e457600080fd5b506101ff60048036038101906101fa9190611df6565b610661565b005b34801561020d57600080fd5b5061022860048036038101906102239190611d42565b6106e7565b005b34801561023657600080fd5b50610251600480360381019061024c9190611d42565b6107a7565b005b34801561025f57600080fd5b50610268610b10565b604051610275919061240c565b60405180910390f35b34801561028a57600080fd5b50610293610b16565b6040516102a0919061240c565b60405180910390f35b3480156102b557600080fd5b506102be610b1c565b6040516102cb919061240c565b60405180910390f35b3480156102e057600080fd5b506102fb60048036038101906102f69190611ea3565b610b22565b005b34801561030957600080fd5b50610312610c6f565b005b34801561032057600080fd5b5061033b60048036038101906103369190611df6565b610cf7565b005b34801561034957600080fd5b50610352610db4565b60405161035f919061240c565b60405180910390f35b34801561037457600080fd5b5061038f600480360381019061038a9190611d42565b610dba565b005b34801561039d57600080fd5b506103a6610f9a565b6040516103b39190612176565b60405180910390f35b3480156103c857600080fd5b506103e360048036038101906103de9190611df6565b610fc3565b005b3480156103f157600080fd5b506103fa611049565b6040516104079190612176565b60405180910390f35b34801561041c57600080fd5b5061042561106f565b604051610432919061240c565b60405180910390f35b34801561044757600080fd5b50610450611075565b60405161045d9190612191565b60405180910390f35b34801561047257600080fd5b5061047b61109b565b604051610488919061240c565b60405180910390f35b34801561049d57600080fd5b506104b860048036038101906104b39190611e50565b6110a1565b005b6104d460048036038101906104cf9190611df6565b61141f565b005b3480156104e257600080fd5b506104fd60048036038101906104f89190611df6565b61189b565b60405161050d949392919061220c565b60405180910390f35b34801561052257600080fd5b5061052b6118eb565b005b34801561053957600080fd5b506105426119b7565b60405161054f919061240c565b60405180910390f35b34801561056457600080fd5b5061057f600480360381019061057a9190611d42565b6119bd565b005b600b6020528060005260406000206000915054906101000a900460ff1681565b6105a9611ab5565b73ffffffffffffffffffffffffffffffffffffffff166105c7610f9a565b73ffffffffffffffffffffffffffffffffffffffff161461061d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610614906123ac565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610669611ab5565b73ffffffffffffffffffffffffffffffffffffffff16610687610f9a565b73ffffffffffffffffffffffffffffffffffffffff16146106dd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d4906123ac565b60405180910390fd5b8060058190555050565b6106ef611ab5565b73ffffffffffffffffffffffffffffffffffffffff1661070d610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614610763576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161075a906123ac565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6107af611ab5565b73ffffffffffffffffffffffffffffffffffffffff166107cd610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614610823576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161081a906123ac565b60405180910390fd5b60008190508073ffffffffffffffffffffffffffffffffffffffff16639d76ea586040518163ffffffff1660e01b815260040160206040518083038186803b15801561086e57600080fd5b505afa158015610882573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a69190611d6f565b600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff1663c424dad86040518163ffffffff1660e01b815260040160206040518083038186803b15801561092c57600080fd5b505afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109649190611d9c565b600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506109e6826040518060400160405280601681526020017f7061796f7574526174696f4e6f6d696e61746f72282900000000000000000000815250600354611abd565b600381905550610a2e826040518060400160405280601881526020017f7061796f7574526174696f44656e6f6d696e61746f7228290000000000000000815250600454611abd565b600481905550610a76826040518060400160405280601581526020017f6f7574676f696e675472616e7366657246656528290000000000000000000000815250600554611abd565b600581905550610abe826040518060400160405280601781526020017f6d6178696d756d5472616e73666572416d6f756e742829000000000000000000815250600654611abd565b600681905550610b06826040518060400160405280601781526020017f7265717569726564436f6e6669726d6174696f6e732829000000000000000000815250600754611abd565b6007819055505050565b60085481565b600a5481565b60065481565b610b2a611ab5565b73ffffffffffffffffffffffffffffffffffffffff16610b48610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614610b9e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b95906123ac565b60405180910390fd5b60008211610be1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd89061236c565b60405180910390fd5b60008111610c24576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c1b9061238c565b60405180910390fd5b81600381905550806004819055507f407aa9e8efe60db1e1e8c03cbc2e7091c77557058c1cb349b60e90f30900b1c48282604051610c63929190612427565b60405180910390a15050565b610c77611ab5565b73ffffffffffffffffffffffffffffffffffffffff16610c95610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614610ceb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ce2906123ac565b60405180910390fd5b610cf56000611bd4565b565b610cff611ab5565b73ffffffffffffffffffffffffffffffffffffffff16610d1d610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614610d73576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6a906123ac565b60405180910390fd5b806007819055507f9d1f3334630bd26a53d2e3c360b09c02204844312bb0fc411686ab17fb2c1d6a81604051610da9919061240c565b60405180910390a150565b60075481565b610dc2611ab5565b73ffffffffffffffffffffffffffffffffffffffff16610de0610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614610e36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e2d906123ac565b60405180910390fd5b60008190508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb610e5f610f9a565b8373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610e989190612176565b60206040518083038186803b158015610eb057600080fd5b505afa158015610ec4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee89190611e23565b6040518363ffffffff1660e01b8152600401610f059291906121e3565b602060405180830381600087803b158015610f1f57600080fd5b505af1158015610f33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f579190611dc9565b610f96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f8d906122ac565b60405180910390fd5b5050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b610fcb611ab5565b73ffffffffffffffffffffffffffffffffffffffff16610fe9610f9a565b73ffffffffffffffffffffffffffffffffffffffff161461103f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611036906123ac565b60405180910390fd5b8060068190555050565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60055481565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611131576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111289061232c565b60405180910390fd5b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600061118360045461117560035486611c9890919063ffffffff16565b611cae90919063ffffffff16565b9050600b600086815260200190815260200160002060009054906101000a900460ff16156111e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111dd906123cc565b60405180910390fd5b808273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016112209190612176565b60206040518083038186803b15801561123857600080fd5b505afa15801561124c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112709190611e23565b10156112b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112a8906122ec565b60405180910390fd5b600a60008154809291906112c490612632565b91905055506001600b6000600a54815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85836040518363ffffffff1660e01b81526004016113329291906121e3565b602060405180830381600087803b15801561134c57600080fd5b505af1158015611360573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113849190611dc9565b6113c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113ba9061234c565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff16600a547f1db115b0b98fc2771eb09da19d01ccc56860697521f38325667f9612f93d851085844360405161141093929190612450565b60405180910390a35050505050565b600554341015611464576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161145b9061226c565b60405180910390fd5b6006548111158061147757506000600654145b6114b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114ad9061228c565b60405180910390fd5b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905060008173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016115189190612176565b60206040518083038186803b15801561153057600080fd5b505afa158015611544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115689190611e23565b90508173ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b81526004016115a7939291906121ac565b602060405180830381600087803b1580156115c157600080fd5b505af11580156115d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115f99190611dc9565b611638576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161162f9061230c565b60405180910390fd5b6000838261164691906124c4565b9050808373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016116829190612176565b60206040518083038186803b15801561169a57600080fd5b505afa1580156116ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d29190611e23565b1015611713576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161170a906123ec565b60405180910390fd5b6008600081548092919061172690612632565b9190505550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f19350505050158015611793573d6000803e3d6000fd5b503360096000600854815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508360096000600854815260200190815260200160002060010181905550436009600060085481526020019081526020016000206002018190555042600960006008548152602001908152602001600020600301819055503373ffffffffffffffffffffffffffffffffffffffff166008547f1db3781f476c924e2c5b9f57e251bfbca1718c38e4b378f90bda83fe084afa9c864360405161188d929190612427565b60405180910390a350505050565b60096020528060005260406000206000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154908060020154908060030154905084565b6118f3611ab5565b73ffffffffffffffffffffffffffffffffffffffff16611911610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614611967576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161195e906123ac565b60405180910390fd5b61196f610f9a565b73ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f193505050501580156119b4573d6000803e3d6000fd5b50565b60045481565b6119c5611ab5565b73ffffffffffffffffffffffffffffffffffffffff166119e3610f9a565b73ffffffffffffffffffffffffffffffffffffffff1614611a39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a30906123ac565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611aa9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aa0906122cc565b60405180910390fd5b611ab281611bd4565b50565b600033905090565b60008060008573ffffffffffffffffffffffffffffffffffffffff168560405160240160405160208183030381529060405290604051611afd919061215f565b60405180910390207bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051611b5f9190612148565b600060405180830381855afa9150503d8060008114611b9a576040519150601f19603f3d011682016040523d82523d6000602084013e611b9f565b606091505b50915091508115611bc75780806020019051810190611bbe9190611e23565b92505050611bcd565b83925050505b9392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008183611ca6919061254b565b905092915050565b60008183611cbc919061251a565b905092915050565b600081359050611cd381612abb565b92915050565b600081519050611ce881612abb565b92915050565b600081519050611cfd81612ad2565b92915050565b600081519050611d1281612ae9565b92915050565b600081359050611d2781612b00565b92915050565b600081519050611d3c81612b00565b92915050565b600060208284031215611d5857611d576126d9565b5b6000611d6684828501611cc4565b91505092915050565b600060208284031215611d8557611d846126d9565b5b6000611d9384828501611cd9565b91505092915050565b600060208284031215611db257611db16126d9565b5b6000611dc084828501611cee565b91505092915050565b600060208284031215611ddf57611dde6126d9565b5b6000611ded84828501611d03565b91505092915050565b600060208284031215611e0c57611e0b6126d9565b5b6000611e1a84828501611d18565b91505092915050565b600060208284031215611e3957611e386126d9565b5b6000611e4784828501611d2d565b91505092915050565b600080600060608486031215611e6957611e686126d9565b5b6000611e7786828701611d18565b9350506020611e8886828701611cc4565b9250506040611e9986828701611d18565b9150509250925092565b60008060408385031215611eba57611eb96126d9565b5b6000611ec885828601611d18565b9250506020611ed985828601611d18565b9150509250929050565b611eec816125b7565b82525050565b611efb816125a5565b82525050565b611f0a816125c9565b82525050565b6000611f1b82612487565b611f25818561249d565b9350611f358185602086016125ff565b80840191505092915050565b6000611f4c82612492565b611f5681856124b9565b9350611f668185602086016125ff565b80840191505092915050565b6000611f7f6040836124a8565b9150611f8a826126de565b604082019050919050565b6000611fa26034836124a8565b9150611fad8261272d565b604082019050919050565b6000611fc56019836124a8565b9150611fd08261277c565b602082019050919050565b6000611fe86026836124a8565b9150611ff3826127a5565b604082019050919050565b600061200b6029836124a8565b9150612016826127f4565b604082019050919050565b600061202e605f836124a8565b915061203982612843565b606082019050919050565b60006120516036836124a8565b915061205c826128b8565b604082019050919050565b6000612074602f836124a8565b915061207f82612907565b604082019050919050565b60006120976023836124a8565b91506120a282612956565b604082019050919050565b60006120ba6025836124a8565b91506120c5826129a5565b604082019050919050565b60006120dd6020836124a8565b91506120e8826129f4565b602082019050919050565b60006121006020836124a8565b915061210b82612a1d565b602082019050919050565b6000612123604d836124a8565b915061212e82612a46565b606082019050919050565b612142816125f5565b82525050565b60006121548284611f10565b915081905092915050565b600061216b8284611f41565b915081905092915050565b600060208201905061218b6000830184611ef2565b92915050565b60006020820190506121a66000830184611ee3565b92915050565b60006060820190506121c16000830186611ef2565b6121ce6020830185611ef2565b6121db6040830184612139565b949350505050565b60006040820190506121f86000830185611ef2565b6122056020830184612139565b9392505050565b60006080820190506122216000830187611ef2565b61222e6020830186612139565b61223b6040830185612139565b6122486060830184612139565b95945050505050565b60006020820190506122666000830184611f01565b92915050565b6000602082019050818103600083015261228581611f72565b9050919050565b600060208201905081810360008301526122a581611f95565b9050919050565b600060208201905081810360008301526122c581611fb8565b9050919050565b600060208201905081810360008301526122e581611fdb565b9050919050565b6000602082019050818103600083015261230581611ffe565b9050919050565b6000602082019050818103600083015261232581612021565b9050919050565b6000602082019050818103600083015261234581612044565b9050919050565b6000602082019050818103600083015261236581612067565b9050919050565b600060208201905081810360008301526123858161208a565b9050919050565b600060208201905081810360008301526123a5816120ad565b9050919050565b600060208201905081810360008301526123c5816120d0565b9050919050565b600060208201905081810360008301526123e5816120f3565b9050919050565b6000602082019050818103600083015261240581612116565b9050919050565b60006020820190506124216000830184612139565b92915050565b600060408201905061243c6000830185612139565b6124496020830184612139565b9392505050565b60006060820190506124656000830186612139565b6124726020830185612139565b61247f6040830184612139565b949350505050565b600081519050919050565b600081519050919050565b600081905092915050565b600082825260208201905092915050565b600081905092915050565b60006124cf826125f5565b91506124da836125f5565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561250f5761250e61267b565b5b828201905092915050565b6000612525826125f5565b9150612530836125f5565b9250826125405761253f6126aa565b5b828204905092915050565b6000612556826125f5565b9150612561836125f5565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561259a5761259961267b565b5b828202905092915050565b60006125b0826125d5565b9050919050565b60006125c2826125d5565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b8381101561261d578082015181840152602081019050612602565b8381111561262c576000848401525b50505050565b600061263d826125f5565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156126705761266f61267b565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600080fd5b7f556e64657270616964207472616e73616374696f6e3a20706c6561736520707260008201527f6f7669646520746865206f7574676f696e67207472616e73666572206665652e602082015250565b7f52657175657374656420616d6f756e742065786365656473206d6178696d756d60008201527f20616d6f756e7420746f207472616e736665722e000000000000000000000000602082015250565b7f4661696c656420746f207472616e7366657220746f6b656e7300000000000000600082015250565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b7f546f6b656e206465706f73697420696e73756666696369656e7420666f72207360008201527f6574746c656d656e740000000000000000000000000000000000000000000000602082015250565b7f5472616e7366657272696e6720746f6b656e73207761732063616e63656c6c6560008201527f642062792074686520746f6b656e20636f6e74726163742e20506c656173652060208201527f636865636b20776974682074686520746f6b656e20646576656c6f7065722e00604082015250565b7f5468697320616374696f6e2063616e206f6e6c7920626520657865637574656460008201527f2062792074686520736574746c696e67206167656e7400000000000000000000602082015250565b7f4661696c656420746f2073656e6420746f6b656e7320746f207468652072656360008201527f656976696e67206163636f756e742e0000000000000000000000000000000000602082015250565b7f4e6f6d696e61746f72206d7573742062652067726561746572207468616e207a60008201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b7f44656e6f6d696e61746f72206d7573742062652067726561746572207468616e60008201527f207a65726f000000000000000000000000000000000000000000000000000000602082015250565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b7f5468697320726571756573742077617320616c726561647920736574746c6564600082015250565b7f446964206e6f74207265636569766520656e6f75676820746f6b656e7320667260008201527f6f6d2073656e6465722e2049732074686520627269646765206578656d70746560208201527f642066726f6d2074617865733f00000000000000000000000000000000000000604082015250565b612ac4816125a5565b8114612acf57600080fd5b50565b612adb816125b7565b8114612ae657600080fd5b50565b612af2816125c9565b8114612afd57600080fd5b50565b612b09816125f5565b8114612b1457600080fd5b5056fea2646970667358221220dbe94de5043ce5f835e82d63a6f856fa7403287683d31ecc004a822f5726033064736f6c63430008060033