ETH Price: $3,395.18 (+1.81%)

Contract

0x3b4837C9F4A606b71e61FD56Db6241781194df92
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Swap Transfer Wi...214645362024-12-23 10:17:475 days ago1734949067IN
0x3b4837C9...81194df92
0 ETH0.002384248.3
Swap Transfer Wi...214498652024-12-21 9:03:597 days ago1734771839IN
0x3b4837C9...81194df92
0 ETH0.0029492210.80060533
Swap Transfer Wi...214031992024-12-14 20:40:2314 days ago1734208823IN
0x3b4837C9...81194df92
0 ETH0.002206758.08155234
Swap Transfer Wi...213965322024-12-13 22:19:4714 days ago1734128387IN
0x3b4837C9...81194df92
0 ETH0.0033629112.30298421
Swap Transfer Wi...213952172024-12-13 17:55:1115 days ago1734112511IN
0x3b4837C9...81194df92
0 ETH0.0057947921.22069561
Swap Transfer Wi...213892572024-12-12 21:56:5915 days ago1734040619IN
0x3b4837C9...81194df92
0 ETH0.0062303119.04235592
Swap Transfer Wi...213376672024-12-05 17:04:4723 days ago1733418287IN
0x3b4837C9...81194df92
0 ETH0.0074287127.5
Swap Transfer Wi...213344872024-12-05 6:25:1123 days ago1733379911IN
0x3b4837C9...81194df92
0 ETH0.0060717421.13594691
Swap Transfer Wi...213343952024-12-05 6:06:3523 days ago1733378795IN
0x3b4837C9...81194df92
0 ETH0.0051771818.93957505
Swap Transfer Wi...213343812024-12-05 6:03:4723 days ago1733378627IN
0x3b4837C9...81194df92
0 ETH0.0054198818.86837021
Swap Transfer Wi...213233392024-12-03 17:02:2325 days ago1733245343IN
0x3b4837C9...81194df92
0 ETH0.0088192832.64625488
Swap Transfer Wi...213106532024-12-01 22:28:5926 days ago1733092139IN
0x3b4837C9...81194df92
0 ETH0.0039370514.41885692
Swap Transfer Wi...213100362024-12-01 20:25:3527 days ago1733084735IN
0x3b4837C9...81194df92
0 ETH0.0069624223.99502699
Swap Transfer Wi...212859612024-11-28 11:40:1130 days ago1732794011IN
0x3b4837C9...81194df92
0 ETH0.00200397.41816323
Swap Transfer Wi...212853022024-11-28 9:27:5930 days ago1732786079IN
0x3b4837C9...81194df92
0 ETH0.002166527.54268843
Swap Transfer Wi...212842582024-11-28 5:54:3530 days ago1732773275IN
0x3b4837C9...81194df92
0 ETH0.002836069.77411119
Swap Transfer Wi...212734082024-11-26 17:26:3532 days ago1732641995IN
0x3b4837C9...81194df92
0 ETH0.0034877812.91011511
Swap Transfer Wi...212385962024-11-21 20:48:3537 days ago1732222115IN
0x3b4837C9...81194df92
0 ETH0.0057129219.68962472
Swap Transfer Wi...212358302024-11-21 11:33:3537 days ago1732188815IN
0x3b4837C9...81194df92
0 ETH0.0043812516.21876781
Swap Transfer Wi...212240792024-11-19 20:09:4739 days ago1732046987IN
0x3b4837C9...81194df92
0 ETH0.0053305619.52065964
Swap Transfer Wi...212147272024-11-18 12:53:1140 days ago1731934391IN
0x3b4837C9...81194df92
0 ETH0.0030857910.74265547
Swap Transfer Wi...212062352024-11-17 8:28:5941 days ago1731832139IN
0x3b4837C9...81194df92
0 ETH0.0029200210.16596322
Swap Transfer Wi...211935262024-11-15 13:55:3543 days ago1731678935IN
0x3b4837C9...81194df92
0 ETH0.0089362232.28043258
Swap Transfer Wi...211935132024-11-15 13:52:5943 days ago1731678779IN
0x3b4837C9...81194df92
0 ETH0.0099494234.25344864
Swap Transfer Wi...211869592024-11-14 15:54:4744 days ago1731599687IN
0x3b4837C9...81194df92
0 ETH0.0091455633.4927463
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
146602802022-04-26 12:58:45977 days ago1650977925  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC20SwapToConversion

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 11 : ERC20SwapToConversion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import './lib/SafeERC20.sol';
import './interfaces/IERC20ConversionProxy.sol';
import './ChainlinkConversionPath.sol';

interface ISwapRouter {
  function swapTokensForExactTokens(
    uint256 amountOut,
    uint256 amountInMax,
    address[] calldata path,
    address to,
    uint256 deadline
  ) external returns (uint256[] memory amounts);
}

/**
 * @title ERC20SwapToConversion
 * @notice This contract swaps ERC20 tokens before paying a request thanks to a payment proxy
 */
contract ERC20SwapToConversion is Ownable {
  using SafeERC20 for IERC20;

  ISwapRouter public swapRouter;
  ChainlinkConversionPath public chainlinkConversionPath;

  // Fees taken by request when a payment is made through swap. Range 0-1000. 10 => 1% fees.
  uint256 public requestSwapFees;

  constructor(address _owner) {
    _transferOwnership(_owner);
  }

  /**
* @notice Performs a request payment, denominated in a token or currency A,
*         where the issuer expects a token B, and the payer uses a token C.
*         The conversion rate from A to B is done using Chainlink.
*         The token swap is done using UniswapV2 or equivalent.
* @param _paymentProxy Address of the ERC20ConversionProxy which will perform the payment.
* @param _to Transfer recipient = request issuer
* @param _requestAmount Amount to transfer in request currency
* @param _amountInMax Maximum amount allowed to spend for currency swap, in payment network currency.
        This amount should take into account the fees.
@param _swapRouterPath, path of ERC20 tokens to swap from spentToken to expectedToken. The first
        address of the path should be the spent currency. The last element should be the
        expected currency.
@param _chainlinkPath, path of currencies to convert from invoicing currency to expectedToken. The first
        address of the path should be the invoicing currency. The last element should be the
        expected currency.
* @param _paymentReference Reference of the payment related
* @param _requestFeeAmount Amount of the fee in request currency
* @param _feeAddress Where to pay the fee
* @param _deadline Deadline for the swap to be valid
* @param _chainlinkMaxRateTimespan Max time span with the oldestrate, ignored if zero
*/
  function swapTransferWithReference(
    address _paymentProxy,
    address _to,
    uint256 _requestAmount, // requestCurrency
    uint256 _amountInMax, // SpentToken
    address[] memory _swapRouterPath, // from spentToken to expectedToken on the swap router
    address[] memory _chainlinkPath, // from invoicingCurrency to expectedToken on chainlink
    bytes memory _paymentReference,
    uint256 _requestFeeAmount, // requestCurrency
    address _feeAddress,
    uint256 _deadline,
    uint256 _chainlinkMaxRateTimespan
  ) external {
    require(
      _swapRouterPath[_swapRouterPath.length - 1] == _chainlinkPath[_chainlinkPath.length - 1],
      'the requested token on the swap router must be the payment currency'
    );
    require(_feeAddress != address(0), 'Invalid fee addres');

    // Get the amount to pay in paymentNetworkToken
    uint256 paymentNetworkTotalAmount = _getConversion(
      _chainlinkPath,
      _requestAmount,
      _requestFeeAmount
    );

    // Compute the request swap fees
    uint256 requestSwapFeesAmount = (paymentNetworkTotalAmount * requestSwapFees) / 1000;

    require(
      IERC20(_swapRouterPath[0]).safeTransferFrom(msg.sender, address(this), _amountInMax),
      'Could not transfer payment token from swapper-payer'
    );

    _swapAndApproveIfNeeded(
      _paymentProxy,
      _amountInMax,
      _swapRouterPath,
      _deadline,
      paymentNetworkTotalAmount + requestSwapFeesAmount
    );

    IERC20ConversionProxy paymentProxy = IERC20ConversionProxy(_paymentProxy);
    // Pay the request and fees
    try
      paymentProxy.transferFromWithReferenceAndFee(
        _to,
        _requestAmount,
        _chainlinkPath,
        _paymentReference,
        _requestFeeAmount,
        _feeAddress,
        paymentNetworkTotalAmount, // _maxToSpend
        _chainlinkMaxRateTimespan
      )
    {} catch (
      bytes memory /*lowLevelData*/
    ) {
      revert('Invalid payment proxy');
    }

    // Pay the request swap fees
    IERC20(_swapRouterPath[_swapRouterPath.length - 1]).safeTransfer(
      _feeAddress,
      requestSwapFeesAmount
    );

    // Give the change back to the payer, in both currencies (only spent token should remain)
    if (IERC20(_swapRouterPath[0]).balanceOf(address(this)) > 0) {
      IERC20(_swapRouterPath[0]).safeTransfer(
        msg.sender,
        IERC20(_swapRouterPath[0]).balanceOf(address(this))
      );
    }
    if (IERC20(_swapRouterPath[_swapRouterPath.length - 1]).balanceOf(address(this)) > 0) {
      IERC20(_swapRouterPath[_swapRouterPath.length - 1]).safeTransfer(
        msg.sender,
        IERC20(_swapRouterPath[_swapRouterPath.length - 1]).balanceOf(address(this))
      );
    }
  }

  /**
   * @notice Authorizes the proxy to spend a new request currency (ERC20).
   * @param _erc20Address Address of an ERC20 used as a request currency
   * @param _paymentProxy Address of the payment proxy to approve
   */
  function approvePaymentProxyToSpend(address _erc20Address, address _paymentProxy) public {
    IERC20 erc20 = IERC20(_erc20Address);
    uint256 max = 2**256 - 1;
    erc20.safeApprove(_paymentProxy, max);
  }

  /**
   * @notice Authorizes the swap router to spend a new payment currency (ERC20).
   * @param _erc20Address Address of an ERC20 used for payment
   */
  function approveRouterToSpend(address _erc20Address) public {
    IERC20 erc20 = IERC20(_erc20Address);
    uint256 max = 2**256 - 1;
    erc20.safeApprove(address(swapRouter), max);
  }

  /*
   * Admin functions to edit the router address, the fees amount and the fees collector address
   */
  function setRouter(address _newSwapRouterAddress) public onlyOwner {
    swapRouter = ISwapRouter(_newSwapRouterAddress);
  }

  function updateRequestSwapFees(uint256 _newRequestSwapFees) public onlyOwner {
    requestSwapFees = _newRequestSwapFees;
  }

  function updateConversionPathAddress(address _chainlinkConversionPath) public onlyOwner {
    chainlinkConversionPath = ChainlinkConversionPath(_chainlinkConversionPath);
  }

  /*
   * Internal functions to reduce the stack in swapTransferWithReference()
   */
  function _getConversion(
    address[] memory _path,
    uint256 _requestAmount,
    uint256 _requestFeeAmount
  ) internal view returns (uint256 conversion) {
    (conversion, ) = chainlinkConversionPath.getConversion(
      _requestAmount + _requestFeeAmount,
      _path
    );
  }

  /**
   * Internal functions to reduce the stack in swapTransferWithReference()
   * Approve the SwapRouter to spend the spentToken if needed
   * Swap the spentToken in exchange for the expectedToken
   * Approve the payment proxy to spend the expected token if needed.
   */
  function _swapAndApproveIfNeeded(
    address _paymentProxy,
    uint256 _amountInMax, // SpentToken
    address[] memory _swapRouterPath, // from spentToken to expectedToken on the swap router
    uint256 _deadline,
    uint256 _paymentNetworkTotalAmount
  ) internal {
    IERC20 spentToken = IERC20(_swapRouterPath[0]);
    // Allow the router to spend all this contract's spentToken
    if (spentToken.allowance(address(this), address(swapRouter)) < _amountInMax) {
      approveRouterToSpend(address(spentToken));
    }

    swapRouter.swapTokensForExactTokens(
      _paymentNetworkTotalAmount,
      _amountInMax,
      _swapRouterPath,
      address(this),
      _deadline
    );

    IERC20 requestedToken = IERC20(_swapRouterPath[_swapRouterPath.length - 1]);

    // Allow the payment network to spend all this contract's requestedToken
    if (requestedToken.allowance(address(this), _paymentProxy) < _paymentNetworkTotalAmount) {
      approvePaymentProxyToSpend(address(requestedToken), _paymentProxy);
    }
  }
}

File 2 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        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);
}

File 3 of 11 : 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);
    }
}

File 4 of 11 : SafeERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';

/**
 * @title SafeERC20
 * @notice Works around implementations of ERC20 with transferFrom not returning success status.
 */
library SafeERC20 {
  /**
   * @notice Call transferFrom ERC20 function and validates the return data of a ERC20 contract call.
   * @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
   * @return result The return value of the ERC20 call, returning true for non-standard tokens
   */
  function safeTransferFrom(
    IERC20 _token,
    address _from,
    address _to,
    uint256 _amount
  ) internal returns (bool result) {
    // solium-disable-next-line security/no-low-level-calls
    (bool success, bytes memory data) = address(_token).call(
      abi.encodeWithSignature('transferFrom(address,address,uint256)', _from, _to, _amount)
    );

    return success && (data.length == 0 || abi.decode(data, (bool)));
  }

  /**
   * @notice Call approve ERC20 function and validates the return data of a ERC20 contract call.
   * @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
   * @return result The return value of the ERC20 call, returning true for non-standard tokens
   */
  function safeApprove(
    IERC20 _token,
    address _spender,
    uint256 _amount
  ) internal returns (bool result) {
    // solium-disable-next-line security/no-low-level-calls
    (bool success, bytes memory data) = address(_token).call(
      abi.encodeWithSignature('approve(address,uint256)', _spender, _amount)
    );

    return success && (data.length == 0 || abi.decode(data, (bool)));
  }

  /**
   * @notice Call transfer ERC20 function and validates the return data of a ERC20 contract call.
   * @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
   * @return result The return value of the ERC20 call, returning true for non-standard tokens
   */
  function safeTransfer(
    IERC20 _token,
    address _to,
    uint256 _amount
  ) internal returns (bool result) {
    // solium-disable-next-line security/no-low-level-calls
    (bool success, bytes memory data) = address(_token).call(
      abi.encodeWithSignature('transfer(address,uint256)', _to, _amount)
    );

    return success && (data.length == 0 || abi.decode(data, (bool)));
  }
}

File 5 of 11 : IERC20ConversionProxy.sol
pragma solidity ^0.8.0;

interface IERC20ConversionProxy {
  // Event to declare a conversion with a reference
  event TransferWithConversionAndReference(
    uint256 amount,
    address currency,
    bytes indexed paymentReference,
    uint256 feeAmount,
    uint256 maxRateTimespan
  );

  // Event to declare a transfer with a reference
  event TransferWithReferenceAndFee(
    address tokenAddress,
    address to,
    uint256 amount,
    bytes indexed paymentReference,
    uint256 feeAmount,
    address feeAddress
  );

  function transferFromWithReferenceAndFee(
    address _to,
    uint256 _requestAmount,
    address[] calldata _path,
    bytes calldata _paymentReference,
    uint256 _feeAmount,
    address _feeAddress,
    uint256 _maxToSpend,
    uint256 _maxRateTimespan
  ) external;
}

File 6 of 11 : ChainlinkConversionPath.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import './legacy_openzeppelin/contracts/access/roles/WhitelistAdminRole.sol';

interface ERC20fraction {
  function decimals() external view returns (uint8);
}

interface AggregatorFraction {
  function decimals() external view returns (uint8);

  function latestAnswer() external view returns (int256);

  function latestTimestamp() external view returns (uint256);
}

/**
 * @title ChainlinkConversionPath
 *
 * @notice ChainlinkConversionPath is a contract computing currency conversion rates based on Chainlink aggretators
 */
contract ChainlinkConversionPath is WhitelistAdminRole {
  uint256 constant PRECISION = 1e18;
  uint256 constant NATIVE_TOKEN_DECIMALS = 18;
  uint256 constant FIAT_DECIMALS = 8;
  address public nativeTokenHash;

  /**
   * @param _nativeTokenHash hash of the native token
   */
  constructor(address _nativeTokenHash) {
    nativeTokenHash = _nativeTokenHash;
  }

  // Mapping of Chainlink aggregators (input currency => output currency => contract address)
  // input & output currencies are the addresses of the ERC20 contracts OR the sha3("currency code")
  mapping(address => mapping(address => address)) public allAggregators;

  // declare a new aggregator
  event AggregatorUpdated(address _input, address _output, address _aggregator);

  /**
   * @notice Update an aggregator
   * @param _input address representing the input currency
   * @param _output address representing the output currency
   * @param _aggregator address of the aggregator contract
   */
  function updateAggregator(
    address _input,
    address _output,
    address _aggregator
  ) external onlyWhitelistAdmin {
    allAggregators[_input][_output] = _aggregator;
    emit AggregatorUpdated(_input, _output, _aggregator);
  }

  /**
   * @notice Update a list of aggregators
   * @param _inputs list of addresses representing the input currencies
   * @param _outputs list of addresses representing the output currencies
   * @param _aggregators list of addresses of the aggregator contracts
   */
  function updateAggregatorsList(
    address[] calldata _inputs,
    address[] calldata _outputs,
    address[] calldata _aggregators
  ) external onlyWhitelistAdmin {
    require(_inputs.length == _outputs.length, 'arrays must have the same length');
    require(_inputs.length == _aggregators.length, 'arrays must have the same length');

    // For every conversions of the path
    for (uint256 i; i < _inputs.length; i++) {
      allAggregators[_inputs[i]][_outputs[i]] = _aggregators[i];
      emit AggregatorUpdated(_inputs[i], _outputs[i], _aggregators[i]);
    }
  }

  /**
   * @notice Computes the conversion of an amount through a list of intermediate conversions
   * @param _amountIn Amount to convert
   * @param _path List of addresses representing the currencies for the intermediate conversions
   * @return result The result after all the conversions
   * @return oldestRateTimestamp The oldest timestamp of the path
   */
  function getConversion(uint256 _amountIn, address[] calldata _path)
    external
    view
    returns (uint256 result, uint256 oldestRateTimestamp)
  {
    (uint256 rate, uint256 timestamp, uint256 decimals) = getRate(_path);

    // initialize the result
    result = (_amountIn * rate) / decimals;

    oldestRateTimestamp = timestamp;
  }

  /**
   * @notice Computes the conversion rate from a list of currencies
   * @param _path List of addresses representing the currencies for the conversions
   * @return rate The rate
   * @return oldestRateTimestamp The oldest timestamp of the path
   * @return decimals of the conversion rate
   */
  function getRate(address[] memory _path)
    public
    view
    returns (
      uint256 rate,
      uint256 oldestRateTimestamp,
      uint256 decimals
    )
  {
    // initialize the result with 18 decimals (for more precision)
    rate = PRECISION;
    decimals = PRECISION;
    oldestRateTimestamp = block.timestamp;

    // For every conversion of the path
    for (uint256 i; i < _path.length - 1; i++) {
      (
        AggregatorFraction aggregator,
        bool reverseAggregator,
        uint256 decimalsInput,
        uint256 decimalsOutput
      ) = getAggregatorAndDecimals(_path[i], _path[i + 1]);

      // store the latest timestamp of the path
      uint256 currentTimestamp = aggregator.latestTimestamp();
      if (currentTimestamp < oldestRateTimestamp) {
        oldestRateTimestamp = currentTimestamp;
      }

      // get the rate of the current step
      uint256 currentRate = uint256(aggregator.latestAnswer());
      // get the number of decimals of the current rate
      uint256 decimalsAggregator = uint256(aggregator.decimals());

      // mul with the difference of decimals before the current rate computation (for more precision)
      if (decimalsAggregator > decimalsInput) {
        rate = rate * (10**(decimalsAggregator - decimalsInput));
      }
      if (decimalsAggregator < decimalsOutput) {
        rate = rate * (10**(decimalsOutput - decimalsAggregator));
      }

      // Apply the current rate (if path uses an aggregator in the reverse way, div instead of mul)
      if (reverseAggregator) {
        rate = (rate * (10**decimalsAggregator)) / currentRate;
      } else {
        rate = (rate * currentRate) / (10**decimalsAggregator);
      }

      // div with the difference of decimals AFTER the current rate computation (for more precision)
      if (decimalsAggregator < decimalsInput) {
        rate = rate / (10**(decimalsInput - decimalsAggregator));
      }
      if (decimalsAggregator > decimalsOutput) {
        rate = rate / (10**(decimalsAggregator - decimalsOutput));
      }
    }
  }

  /**
   * @notice Gets aggregators and decimals of two currencies
   * @param _input input Address
   * @param _output output Address
   * @return aggregator to get the rate between the two currencies
   * @return reverseAggregator true if the aggregator returned give the rate from _output to _input
   * @return decimalsInput decimals of _input
   * @return decimalsOutput decimals of _output
   */
  function getAggregatorAndDecimals(address _input, address _output)
    private
    view
    returns (
      AggregatorFraction aggregator,
      bool reverseAggregator,
      uint256 decimalsInput,
      uint256 decimalsOutput
    )
  {
    // Try to get the right aggregator for the conversion
    aggregator = AggregatorFraction(allAggregators[_input][_output]);
    reverseAggregator = false;

    // if no aggregator found we try to find an aggregator in the reverse way
    if (address(aggregator) == address(0x00)) {
      aggregator = AggregatorFraction(allAggregators[_output][_input]);
      reverseAggregator = true;
    }

    require(address(aggregator) != address(0x00), 'No aggregator found');

    // get the decimals for the two currencies
    decimalsInput = getDecimals(_input);
    decimalsOutput = getDecimals(_output);
  }

  /**
   * @notice Gets decimals from an address currency
   * @param _addr address to check
   * @return decimals number of decimals
   */
  function getDecimals(address _addr) private view returns (uint256 decimals) {
    // by default we assume it is fiat
    decimals = FIAT_DECIMALS;
    // if address is the hash of the ETH currency
    if (_addr == nativeTokenHash) {
      decimals = NATIVE_TOKEN_DECIMALS;
    } else if (isContract(_addr)) {
      // otherwise, we get the decimals from the erc20 directly
      decimals = ERC20fraction(_addr).decimals();
    }
  }

  /**
   * @notice Checks if an address is a contract
   * @param _addr Address to check
   * @return true if the address hosts a contract, false otherwise
   */
  function isContract(address _addr) private view returns (bool) {
    uint32 size;
    // solium-disable security/no-inline-assembly
    assembly {
      size := extcodesize(_addr)
    }
    return (size > 0);
  }
}

File 7 of 11 : 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;
    }
}

File 8 of 11 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        unchecked {
            _approve(sender, _msgSender(), currentAllowance - amount);
        }

        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(_msgSender(), spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[sender] = senderBalance - amount;
        }
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);

        _afterTokenTransfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

File 9 of 11 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 10 of 11 : WhitelistAdminRole.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import '@openzeppelin/contracts/utils/Context.sol';
import '../Roles.sol';

/**
 * @title WhitelistAdminRole
 * @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts.
 */
abstract contract WhitelistAdminRole is Context {
  using Roles for Roles.Role;

  event WhitelistAdminAdded(address indexed account);
  event WhitelistAdminRemoved(address indexed account);

  Roles.Role private _whitelistAdmins;

  constructor() {
    _addWhitelistAdmin(_msgSender());
  }

  modifier onlyWhitelistAdmin() {
    require(
      isWhitelistAdmin(_msgSender()),
      'WhitelistAdminRole: caller does not have the WhitelistAdmin role'
    );
    _;
  }

  function isWhitelistAdmin(address account) public view returns (bool) {
    return _whitelistAdmins.has(account);
  }

  function addWhitelistAdmin(address account) public onlyWhitelistAdmin {
    _addWhitelistAdmin(account);
  }

  function renounceWhitelistAdmin() public {
    _removeWhitelistAdmin(_msgSender());
  }

  function _addWhitelistAdmin(address account) internal {
    _whitelistAdmins.add(account);
    emit WhitelistAdminAdded(account);
  }

  function _removeWhitelistAdmin(address account) internal {
    _whitelistAdmins.remove(account);
    emit WhitelistAdminRemoved(account);
  }
}

File 11 of 11 : Roles.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title Roles
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
  struct Role {
    mapping(address => bool) bearer;
  }

  /**
   * @dev Give an account access to this role.
   */
  function add(Role storage role, address account) internal {
    require(!has(role, account), 'Roles: account already has role');
    role.bearer[account] = true;
  }

  /**
   * @dev Remove an account's access to this role.
   */
  function remove(Role storage role, address account) internal {
    require(has(role, account), 'Roles: account does not have role');
    role.bearer[account] = false;
  }

  /**
   * @dev Check if an account has this role.
   * @return bool
   */
  function has(Role storage role, address account) internal view returns (bool) {
    require(account != address(0), 'Roles: account is the zero address');
    return role.bearer[account];
  }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"_erc20Address","type":"address"},{"internalType":"address","name":"_paymentProxy","type":"address"}],"name":"approvePaymentProxyToSpend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_erc20Address","type":"address"}],"name":"approveRouterToSpend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainlinkConversionPath","outputs":[{"internalType":"contract ChainlinkConversionPath","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestSwapFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newSwapRouterAddress","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentProxy","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_requestAmount","type":"uint256"},{"internalType":"uint256","name":"_amountInMax","type":"uint256"},{"internalType":"address[]","name":"_swapRouterPath","type":"address[]"},{"internalType":"address[]","name":"_chainlinkPath","type":"address[]"},{"internalType":"bytes","name":"_paymentReference","type":"bytes"},{"internalType":"uint256","name":"_requestFeeAmount","type":"uint256"},{"internalType":"address","name":"_feeAddress","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint256","name":"_chainlinkMaxRateTimespan","type":"uint256"}],"name":"swapTransferWithReference","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainlinkConversionPath","type":"address"}],"name":"updateConversionPathAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newRequestSwapFees","type":"uint256"}],"name":"updateRequestSwapFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b50604051620026c7380380620026c78339818101604052810190620000379190620001a5565b620000576200004b6200006f60201b60201c565b6200007760201b60201c565b62000068816200007760201b60201c565b50620001d7565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200016d8262000140565b9050919050565b6200017f8162000160565b81146200018b57600080fd5b50565b6000815190506200019f8162000174565b92915050565b600060208284031215620001be57620001bd6200013b565b5b6000620001ce848285016200018e565b91505092915050565b6124e080620001e76000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063946647f111610071578063946647f114610153578063ad2f5be614610171578063ad6d61061461018d578063c0d78655146101a9578063c31c9c07146101c5578063f2fde38b146101e3576100b4565b80631d7bc74b146100b957806330e175c9146100d55780633e952c1a146100f1578063715018a61461010f5780637a38d1cb146101195780638da5cb5b14610135575b600080fd5b6100d360048036038101906100ce9190611554565b6101ff565b005b6100ef60048036038101906100ea91906115df565b610285565b005b6100f9610302565b604051610106919061161b565b60405180910390f35b610117610308565b005b610133600480360381019061012e91906115df565b610390565b005b61013d610450565b60405161014a9190611645565b60405180910390f35b61015b610479565b60405161016891906116bf565b60405180910390f35b61018b600480360381019061018691906116da565b61049f565b005b6101a760048036038101906101a29190611928565b6104fb565b005b6101c360048036038101906101be91906115df565b610b91565b005b6101cd610c51565b6040516101da9190611a91565b60405180910390f35b6101fd60048036038101906101f891906115df565b610c77565b005b610207610d6f565b73ffffffffffffffffffffffffffffffffffffffff16610225610450565b73ffffffffffffffffffffffffffffffffffffffff161461027b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161027290611b09565b60405180910390fd5b8060038190555050565b600081905060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90506102fc600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff16610d779092919063ffffffff16565b50505050565b60035481565b610310610d6f565b73ffffffffffffffffffffffffffffffffffffffff1661032e610450565b73ffffffffffffffffffffffffffffffffffffffff1614610384576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037b90611b09565b60405180910390fd5b61038e6000610eab565b565b610398610d6f565b73ffffffffffffffffffffffffffffffffffffffff166103b6610450565b73ffffffffffffffffffffffffffffffffffffffff161461040c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040390611b09565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600082905060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90506104f483828473ffffffffffffffffffffffffffffffffffffffff16610d779092919063ffffffff16565b5050505050565b856001875161050a9190611b58565b8151811061051b5761051a611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1687600189516105489190611b58565b8151811061055957610558611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16146105b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90611c53565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061e90611cbf565b60405180910390fd5b6000610634878b87610f6f565b905060006103e8600354836106499190611cdf565b6106539190611d68565b905061069d33308c8c60008151811061066f5761066e611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611034909392919063ffffffff16565b6106dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d390611e0b565b60405180910390fd5b6106f48d8b8b8785876106ef9190611e2b565b61116b565b60008d90508073ffffffffffffffffffffffffffffffffffffffff16633af2c0128e8e8c8c8c8c8a8c6040518963ffffffff1660e01b8152600401610740989796959493929190611fc7565b600060405180830381600087803b15801561075a57600080fd5b505af192505050801561076b575060015b6107dc573d806000811461079b576040519150601f19603f3d011682016040523d82523d6000602084013e6107a0565b606091505b506040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107d39061209f565b60405180910390fd5b61082e86838c60018e516107f09190611b58565b8151811061080157610800611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166113d69092919063ffffffff16565b5060008a60008151811061084557610844611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016108859190611645565b60206040518083038186803b15801561089d57600080fd5b505afa1580156108b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d591906120d4565b11156109c6576109c4338b6000815181106108f3576108f2611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109339190611645565b60206040518083038186803b15801561094b57600080fd5b505afa15801561095f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098391906120d4565b8c60008151811061099757610996611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166113d69092919063ffffffff16565b505b60008a60018c516109d79190611b58565b815181106109e8576109e7611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610a289190611645565b60206040518083038186803b158015610a4057600080fd5b505afa158015610a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7891906120d4565b1115610b8157610b7f338b60018d51610a919190611b58565b81518110610aa257610aa1611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610ae29190611645565b60206040518083038186803b158015610afa57600080fd5b505afa158015610b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3291906120d4565b8c60018e51610b419190611b58565b81518110610b5257610b51611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166113d69092919063ffffffff16565b505b5050505050505050505050505050565b610b99610d6f565b73ffffffffffffffffffffffffffffffffffffffff16610bb7610450565b73ffffffffffffffffffffffffffffffffffffffff1614610c0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c0490611b09565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610c7f610d6f565b73ffffffffffffffffffffffffffffffffffffffff16610c9d610450565b73ffffffffffffffffffffffffffffffffffffffff1614610cf3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cea90611b09565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610d63576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5a90612173565b60405180910390fd5b610d6c81610eab565b50565b600033905090565b60008060008573ffffffffffffffffffffffffffffffffffffffff168585604051602401610da6929190612193565b6040516020818303038152906040527f095ea7b3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610e3091906121f8565b6000604051808303816000865af19150503d8060008114610e6d576040519150601f19603f3d011682016040523d82523d6000602084013e610e72565b606091505b5091509150818015610ea05750600081511480610e9f575080806020019051810190610e9e9190612247565b5b5b925050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fbd4122a8385610fbb9190611e2b565b866040518363ffffffff1660e01b8152600401610fd9929190612274565b604080518083038186803b158015610ff057600080fd5b505afa158015611004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102891906122a4565b50809150509392505050565b60008060008673ffffffffffffffffffffffffffffffffffffffff16868686604051602401611065939291906122e4565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516110ef91906121f8565b6000604051808303816000865af19150503d806000811461112c576040519150601f19603f3d011682016040523d82523d6000602084013e611131565b606091505b509150915081801561115f575060008151148061115e57508080602001905181019061115d9190612247565b5b5b92505050949350505050565b60008360008151811061118157611180611b8c565b5b60200260200101519050848173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b81526004016111e992919061231b565b60206040518083038186803b15801561120157600080fd5b505afa158015611215573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123991906120d4565b10156112495761124881610285565b5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638803dbee83878730886040518663ffffffff1660e01b81526004016112ac959493929190612344565b600060405180830381600087803b1580156112c657600080fd5b505af11580156112da573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906113039190612461565b50600084600186516113159190611b58565b8151811061132657611325611b8c565b5b60200260200101519050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e308a6040518363ffffffff1660e01b815260040161136c92919061231b565b60206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc91906120d4565b10156113cd576113cc818861049f565b5b50505050505050565b60008060008573ffffffffffffffffffffffffffffffffffffffff168585604051602401611405929190612193565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161148f91906121f8565b6000604051808303816000865af19150503d80600081146114cc576040519150601f19603f3d011682016040523d82523d6000602084013e6114d1565b606091505b50915091508180156114ff57506000815114806114fe5750808060200190518101906114fd9190612247565b5b5b925050509392505050565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6115318161151e565b811461153c57600080fd5b50565b60008135905061154e81611528565b92915050565b60006020828403121561156a57611569611514565b5b60006115788482850161153f565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006115ac82611581565b9050919050565b6115bc816115a1565b81146115c757600080fd5b50565b6000813590506115d9816115b3565b92915050565b6000602082840312156115f5576115f4611514565b5b6000611603848285016115ca565b91505092915050565b6116158161151e565b82525050565b6000602082019050611630600083018461160c565b92915050565b61163f816115a1565b82525050565b600060208201905061165a6000830184611636565b92915050565b6000819050919050565b600061168561168061167b84611581565b611660565b611581565b9050919050565b60006116978261166a565b9050919050565b60006116a98261168c565b9050919050565b6116b98161169e565b82525050565b60006020820190506116d460008301846116b0565b92915050565b600080604083850312156116f1576116f0611514565b5b60006116ff858286016115ca565b9250506020611710858286016115ca565b9150509250929050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6117688261171f565b810181811067ffffffffffffffff8211171561178757611786611730565b5b80604052505050565b600061179a61150a565b90506117a6828261175f565b919050565b600067ffffffffffffffff8211156117c6576117c5611730565b5b602082029050602081019050919050565b600080fd5b60006117ef6117ea846117ab565b611790565b90508083825260208201905060208402830185811115611812576118116117d7565b5b835b8181101561183b578061182788826115ca565b845260208401935050602081019050611814565b5050509392505050565b600082601f83011261185a5761185961171a565b5b813561186a8482602086016117dc565b91505092915050565b600080fd5b600067ffffffffffffffff82111561189357611892611730565b5b61189c8261171f565b9050602081019050919050565b82818337600083830152505050565b60006118cb6118c684611878565b611790565b9050828152602081018484840111156118e7576118e6611873565b5b6118f28482856118a9565b509392505050565b600082601f83011261190f5761190e61171a565b5b813561191f8482602086016118b8565b91505092915050565b60008060008060008060008060008060006101608c8e03121561194e5761194d611514565b5b600061195c8e828f016115ca565b9b5050602061196d8e828f016115ca565b9a5050604061197e8e828f0161153f565b995050606061198f8e828f0161153f565b98505060808c013567ffffffffffffffff8111156119b0576119af611519565b5b6119bc8e828f01611845565b97505060a08c013567ffffffffffffffff8111156119dd576119dc611519565b5b6119e98e828f01611845565b96505060c08c013567ffffffffffffffff811115611a0a57611a09611519565b5b611a168e828f016118fa565b95505060e0611a278e828f0161153f565b945050610100611a398e828f016115ca565b935050610120611a4b8e828f0161153f565b925050610140611a5d8e828f0161153f565b9150509295989b509295989b9093969950565b6000611a7b8261168c565b9050919050565b611a8b81611a70565b82525050565b6000602082019050611aa66000830184611a82565b92915050565b600082825260208201905092915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000611af3602083611aac565b9150611afe82611abd565b602082019050919050565b60006020820190508181036000830152611b2281611ae6565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611b638261151e565b9150611b6e8361151e565b925082821015611b8157611b80611b29565b5b828203905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f7468652072657175657374656420746f6b656e206f6e2074686520737761702060008201527f726f75746572206d75737420626520746865207061796d656e7420637572726560208201527f6e63790000000000000000000000000000000000000000000000000000000000604082015250565b6000611c3d604383611aac565b9150611c4882611bbb565b606082019050919050565b60006020820190508181036000830152611c6c81611c30565b9050919050565b7f496e76616c696420666565206164647265730000000000000000000000000000600082015250565b6000611ca9601283611aac565b9150611cb482611c73565b602082019050919050565b60006020820190508181036000830152611cd881611c9c565b9050919050565b6000611cea8261151e565b9150611cf58361151e565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611d2e57611d2d611b29565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611d738261151e565b9150611d7e8361151e565b925082611d8e57611d8d611d39565b5b828204905092915050565b7f436f756c64206e6f74207472616e73666572207061796d656e7420746f6b656e60008201527f2066726f6d20737761707065722d706179657200000000000000000000000000602082015250565b6000611df5603383611aac565b9150611e0082611d99565b604082019050919050565b60006020820190508181036000830152611e2481611de8565b9050919050565b6000611e368261151e565b9150611e418361151e565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611e7657611e75611b29565b5b828201905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611eb6816115a1565b82525050565b6000611ec88383611ead565b60208301905092915050565b6000602082019050919050565b6000611eec82611e81565b611ef68185611e8c565b9350611f0183611e9d565b8060005b83811015611f32578151611f198882611ebc565b9750611f2483611ed4565b925050600181019050611f05565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611f79578082015181840152602081019050611f5e565b83811115611f88576000848401525b50505050565b6000611f9982611f3f565b611fa38185611f4a565b9350611fb3818560208601611f5b565b611fbc8161171f565b840191505092915050565b600061010082019050611fdd600083018b611636565b611fea602083018a61160c565b8181036040830152611ffc8189611ee1565b905081810360608301526120108188611f8e565b905061201f608083018761160c565b61202c60a0830186611636565b61203960c083018561160c565b61204660e083018461160c565b9998505050505050505050565b7f496e76616c6964207061796d656e742070726f78790000000000000000000000600082015250565b6000612089601583611aac565b915061209482612053565b602082019050919050565b600060208201905081810360008301526120b88161207c565b9050919050565b6000815190506120ce81611528565b92915050565b6000602082840312156120ea576120e9611514565b5b60006120f8848285016120bf565b91505092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061215d602683611aac565b915061216882612101565b604082019050919050565b6000602082019050818103600083015261218c81612150565b9050919050565b60006040820190506121a86000830185611636565b6121b5602083018461160c565b9392505050565b600081905092915050565b60006121d282611f3f565b6121dc81856121bc565b93506121ec818560208601611f5b565b80840191505092915050565b600061220482846121c7565b915081905092915050565b60008115159050919050565b6122248161220f565b811461222f57600080fd5b50565b6000815190506122418161221b565b92915050565b60006020828403121561225d5761225c611514565b5b600061226b84828501612232565b91505092915050565b6000604082019050612289600083018561160c565b818103602083015261229b8184611ee1565b90509392505050565b600080604083850312156122bb576122ba611514565b5b60006122c9858286016120bf565b92505060206122da858286016120bf565b9150509250929050565b60006060820190506122f96000830186611636565b6123066020830185611636565b612313604083018461160c565b949350505050565b60006040820190506123306000830185611636565b61233d6020830184611636565b9392505050565b600060a082019050612359600083018861160c565b612366602083018761160c565b81810360408301526123788186611ee1565b90506123876060830185611636565b612394608083018461160c565b9695505050505050565b600067ffffffffffffffff8211156123b9576123b8611730565b5b602082029050602081019050919050565b60006123dd6123d88461239e565b611790565b90508083825260208201905060208402830185811115612400576123ff6117d7565b5b835b81811015612429578061241588826120bf565b845260208401935050602081019050612402565b5050509392505050565b600082601f8301126124485761244761171a565b5b81516124588482602086016123ca565b91505092915050565b60006020828403121561247757612476611514565b5b600082015167ffffffffffffffff81111561249557612494611519565b5b6124a184828501612433565b9150509291505056fea26469706673582212207dca6640f9f7c6efbbc63e24d307c8e42c74cbdab2effc4340482043a31e58d764736f6c634300080900330000000000000000000000004e64c2d06d19d13061e62e291b2c4e9fe5679b93

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100b45760003560e01c8063946647f111610071578063946647f114610153578063ad2f5be614610171578063ad6d61061461018d578063c0d78655146101a9578063c31c9c07146101c5578063f2fde38b146101e3576100b4565b80631d7bc74b146100b957806330e175c9146100d55780633e952c1a146100f1578063715018a61461010f5780637a38d1cb146101195780638da5cb5b14610135575b600080fd5b6100d360048036038101906100ce9190611554565b6101ff565b005b6100ef60048036038101906100ea91906115df565b610285565b005b6100f9610302565b604051610106919061161b565b60405180910390f35b610117610308565b005b610133600480360381019061012e91906115df565b610390565b005b61013d610450565b60405161014a9190611645565b60405180910390f35b61015b610479565b60405161016891906116bf565b60405180910390f35b61018b600480360381019061018691906116da565b61049f565b005b6101a760048036038101906101a29190611928565b6104fb565b005b6101c360048036038101906101be91906115df565b610b91565b005b6101cd610c51565b6040516101da9190611a91565b60405180910390f35b6101fd60048036038101906101f891906115df565b610c77565b005b610207610d6f565b73ffffffffffffffffffffffffffffffffffffffff16610225610450565b73ffffffffffffffffffffffffffffffffffffffff161461027b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161027290611b09565b60405180910390fd5b8060038190555050565b600081905060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90506102fc600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16828473ffffffffffffffffffffffffffffffffffffffff16610d779092919063ffffffff16565b50505050565b60035481565b610310610d6f565b73ffffffffffffffffffffffffffffffffffffffff1661032e610450565b73ffffffffffffffffffffffffffffffffffffffff1614610384576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037b90611b09565b60405180910390fd5b61038e6000610eab565b565b610398610d6f565b73ffffffffffffffffffffffffffffffffffffffff166103b6610450565b73ffffffffffffffffffffffffffffffffffffffff161461040c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161040390611b09565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600082905060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90506104f483828473ffffffffffffffffffffffffffffffffffffffff16610d779092919063ffffffff16565b5050505050565b856001875161050a9190611b58565b8151811061051b5761051a611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1687600189516105489190611b58565b8151811061055957610558611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16146105b7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ae90611c53565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610627576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061e90611cbf565b60405180910390fd5b6000610634878b87610f6f565b905060006103e8600354836106499190611cdf565b6106539190611d68565b905061069d33308c8c60008151811061066f5761066e611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16611034909392919063ffffffff16565b6106dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106d390611e0b565b60405180910390fd5b6106f48d8b8b8785876106ef9190611e2b565b61116b565b60008d90508073ffffffffffffffffffffffffffffffffffffffff16633af2c0128e8e8c8c8c8c8a8c6040518963ffffffff1660e01b8152600401610740989796959493929190611fc7565b600060405180830381600087803b15801561075a57600080fd5b505af192505050801561076b575060015b6107dc573d806000811461079b576040519150601f19603f3d011682016040523d82523d6000602084013e6107a0565b606091505b506040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107d39061209f565b60405180910390fd5b61082e86838c60018e516107f09190611b58565b8151811061080157610800611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166113d69092919063ffffffff16565b5060008a60008151811061084557610844611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016108859190611645565b60206040518083038186803b15801561089d57600080fd5b505afa1580156108b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d591906120d4565b11156109c6576109c4338b6000815181106108f3576108f2611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016109339190611645565b60206040518083038186803b15801561094b57600080fd5b505afa15801561095f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098391906120d4565b8c60008151811061099757610996611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166113d69092919063ffffffff16565b505b60008a60018c516109d79190611b58565b815181106109e8576109e7611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610a289190611645565b60206040518083038186803b158015610a4057600080fd5b505afa158015610a54573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7891906120d4565b1115610b8157610b7f338b60018d51610a919190611b58565b81518110610aa257610aa1611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610ae29190611645565b60206040518083038186803b158015610afa57600080fd5b505afa158015610b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3291906120d4565b8c60018e51610b419190611b58565b81518110610b5257610b51611b8c565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff166113d69092919063ffffffff16565b505b5050505050505050505050505050565b610b99610d6f565b73ffffffffffffffffffffffffffffffffffffffff16610bb7610450565b73ffffffffffffffffffffffffffffffffffffffff1614610c0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c0490611b09565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610c7f610d6f565b73ffffffffffffffffffffffffffffffffffffffff16610c9d610450565b73ffffffffffffffffffffffffffffffffffffffff1614610cf3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cea90611b09565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610d63576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d5a90612173565b60405180910390fd5b610d6c81610eab565b50565b600033905090565b60008060008573ffffffffffffffffffffffffffffffffffffffff168585604051602401610da6929190612193565b6040516020818303038152906040527f095ea7b3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610e3091906121f8565b6000604051808303816000865af19150503d8060008114610e6d576040519150601f19603f3d011682016040523d82523d6000602084013e610e72565b606091505b5091509150818015610ea05750600081511480610e9f575080806020019051810190610e9e9190612247565b5b5b925050509392505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fbd4122a8385610fbb9190611e2b565b866040518363ffffffff1660e01b8152600401610fd9929190612274565b604080518083038186803b158015610ff057600080fd5b505afa158015611004573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102891906122a4565b50809150509392505050565b60008060008673ffffffffffffffffffffffffffffffffffffffff16868686604051602401611065939291906122e4565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516110ef91906121f8565b6000604051808303816000865af19150503d806000811461112c576040519150601f19603f3d011682016040523d82523d6000602084013e611131565b606091505b509150915081801561115f575060008151148061115e57508080602001905181019061115d9190612247565b5b5b92505050949350505050565b60008360008151811061118157611180611b8c565b5b60200260200101519050848173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166040518363ffffffff1660e01b81526004016111e992919061231b565b60206040518083038186803b15801561120157600080fd5b505afa158015611215573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123991906120d4565b10156112495761124881610285565b5b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16638803dbee83878730886040518663ffffffff1660e01b81526004016112ac959493929190612344565b600060405180830381600087803b1580156112c657600080fd5b505af11580156112da573d6000803e3d6000fd5b505050506040513d6000823e3d601f19601f820116820180604052508101906113039190612461565b50600084600186516113159190611b58565b8151811061132657611325611b8c565b5b60200260200101519050828173ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e308a6040518363ffffffff1660e01b815260040161136c92919061231b565b60206040518083038186803b15801561138457600080fd5b505afa158015611398573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bc91906120d4565b10156113cd576113cc818861049f565b5b50505050505050565b60008060008573ffffffffffffffffffffffffffffffffffffffff168585604051602401611405929190612193565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161148f91906121f8565b6000604051808303816000865af19150503d80600081146114cc576040519150601f19603f3d011682016040523d82523d6000602084013e6114d1565b606091505b50915091508180156114ff57506000815114806114fe5750808060200190518101906114fd9190612247565b5b5b925050509392505050565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6115318161151e565b811461153c57600080fd5b50565b60008135905061154e81611528565b92915050565b60006020828403121561156a57611569611514565b5b60006115788482850161153f565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006115ac82611581565b9050919050565b6115bc816115a1565b81146115c757600080fd5b50565b6000813590506115d9816115b3565b92915050565b6000602082840312156115f5576115f4611514565b5b6000611603848285016115ca565b91505092915050565b6116158161151e565b82525050565b6000602082019050611630600083018461160c565b92915050565b61163f816115a1565b82525050565b600060208201905061165a6000830184611636565b92915050565b6000819050919050565b600061168561168061167b84611581565b611660565b611581565b9050919050565b60006116978261166a565b9050919050565b60006116a98261168c565b9050919050565b6116b98161169e565b82525050565b60006020820190506116d460008301846116b0565b92915050565b600080604083850312156116f1576116f0611514565b5b60006116ff858286016115ca565b9250506020611710858286016115ca565b9150509250929050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6117688261171f565b810181811067ffffffffffffffff8211171561178757611786611730565b5b80604052505050565b600061179a61150a565b90506117a6828261175f565b919050565b600067ffffffffffffffff8211156117c6576117c5611730565b5b602082029050602081019050919050565b600080fd5b60006117ef6117ea846117ab565b611790565b90508083825260208201905060208402830185811115611812576118116117d7565b5b835b8181101561183b578061182788826115ca565b845260208401935050602081019050611814565b5050509392505050565b600082601f83011261185a5761185961171a565b5b813561186a8482602086016117dc565b91505092915050565b600080fd5b600067ffffffffffffffff82111561189357611892611730565b5b61189c8261171f565b9050602081019050919050565b82818337600083830152505050565b60006118cb6118c684611878565b611790565b9050828152602081018484840111156118e7576118e6611873565b5b6118f28482856118a9565b509392505050565b600082601f83011261190f5761190e61171a565b5b813561191f8482602086016118b8565b91505092915050565b60008060008060008060008060008060006101608c8e03121561194e5761194d611514565b5b600061195c8e828f016115ca565b9b5050602061196d8e828f016115ca565b9a5050604061197e8e828f0161153f565b995050606061198f8e828f0161153f565b98505060808c013567ffffffffffffffff8111156119b0576119af611519565b5b6119bc8e828f01611845565b97505060a08c013567ffffffffffffffff8111156119dd576119dc611519565b5b6119e98e828f01611845565b96505060c08c013567ffffffffffffffff811115611a0a57611a09611519565b5b611a168e828f016118fa565b95505060e0611a278e828f0161153f565b945050610100611a398e828f016115ca565b935050610120611a4b8e828f0161153f565b925050610140611a5d8e828f0161153f565b9150509295989b509295989b9093969950565b6000611a7b8261168c565b9050919050565b611a8b81611a70565b82525050565b6000602082019050611aa66000830184611a82565b92915050565b600082825260208201905092915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000611af3602083611aac565b9150611afe82611abd565b602082019050919050565b60006020820190508181036000830152611b2281611ae6565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611b638261151e565b9150611b6e8361151e565b925082821015611b8157611b80611b29565b5b828203905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f7468652072657175657374656420746f6b656e206f6e2074686520737761702060008201527f726f75746572206d75737420626520746865207061796d656e7420637572726560208201527f6e63790000000000000000000000000000000000000000000000000000000000604082015250565b6000611c3d604383611aac565b9150611c4882611bbb565b606082019050919050565b60006020820190508181036000830152611c6c81611c30565b9050919050565b7f496e76616c696420666565206164647265730000000000000000000000000000600082015250565b6000611ca9601283611aac565b9150611cb482611c73565b602082019050919050565b60006020820190508181036000830152611cd881611c9c565b9050919050565b6000611cea8261151e565b9150611cf58361151e565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615611d2e57611d2d611b29565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000611d738261151e565b9150611d7e8361151e565b925082611d8e57611d8d611d39565b5b828204905092915050565b7f436f756c64206e6f74207472616e73666572207061796d656e7420746f6b656e60008201527f2066726f6d20737761707065722d706179657200000000000000000000000000602082015250565b6000611df5603383611aac565b9150611e0082611d99565b604082019050919050565b60006020820190508181036000830152611e2481611de8565b9050919050565b6000611e368261151e565b9150611e418361151e565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611e7657611e75611b29565b5b828201905092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611eb6816115a1565b82525050565b6000611ec88383611ead565b60208301905092915050565b6000602082019050919050565b6000611eec82611e81565b611ef68185611e8c565b9350611f0183611e9d565b8060005b83811015611f32578151611f198882611ebc565b9750611f2483611ed4565b925050600181019050611f05565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015611f79578082015181840152602081019050611f5e565b83811115611f88576000848401525b50505050565b6000611f9982611f3f565b611fa38185611f4a565b9350611fb3818560208601611f5b565b611fbc8161171f565b840191505092915050565b600061010082019050611fdd600083018b611636565b611fea602083018a61160c565b8181036040830152611ffc8189611ee1565b905081810360608301526120108188611f8e565b905061201f608083018761160c565b61202c60a0830186611636565b61203960c083018561160c565b61204660e083018461160c565b9998505050505050505050565b7f496e76616c6964207061796d656e742070726f78790000000000000000000000600082015250565b6000612089601583611aac565b915061209482612053565b602082019050919050565b600060208201905081810360008301526120b88161207c565b9050919050565b6000815190506120ce81611528565b92915050565b6000602082840312156120ea576120e9611514565b5b60006120f8848285016120bf565b91505092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061215d602683611aac565b915061216882612101565b604082019050919050565b6000602082019050818103600083015261218c81612150565b9050919050565b60006040820190506121a86000830185611636565b6121b5602083018461160c565b9392505050565b600081905092915050565b60006121d282611f3f565b6121dc81856121bc565b93506121ec818560208601611f5b565b80840191505092915050565b600061220482846121c7565b915081905092915050565b60008115159050919050565b6122248161220f565b811461222f57600080fd5b50565b6000815190506122418161221b565b92915050565b60006020828403121561225d5761225c611514565b5b600061226b84828501612232565b91505092915050565b6000604082019050612289600083018561160c565b818103602083015261229b8184611ee1565b90509392505050565b600080604083850312156122bb576122ba611514565b5b60006122c9858286016120bf565b92505060206122da858286016120bf565b9150509250929050565b60006060820190506122f96000830186611636565b6123066020830185611636565b612313604083018461160c565b949350505050565b60006040820190506123306000830185611636565b61233d6020830184611636565b9392505050565b600060a082019050612359600083018861160c565b612366602083018761160c565b81810360408301526123788186611ee1565b90506123876060830185611636565b612394608083018461160c565b9695505050505050565b600067ffffffffffffffff8211156123b9576123b8611730565b5b602082029050602081019050919050565b60006123dd6123d88461239e565b611790565b90508083825260208201905060208402830185811115612400576123ff6117d7565b5b835b81811015612429578061241588826120bf565b845260208401935050602081019050612402565b5050509392505050565b600082601f8301126124485761244761171a565b5b81516124588482602086016123ca565b91505092915050565b60006020828403121561247757612476611514565b5b600082015167ffffffffffffffff81111561249557612494611519565b5b6124a184828501612433565b9150509291505056fea26469706673582212207dca6640f9f7c6efbbc63e24d307c8e42c74cbdab2effc4340482043a31e58d764736f6c63430008090033

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

0000000000000000000000004e64c2d06d19d13061e62e291b2c4e9fe5679b93

-----Decoded View---------------
Arg [0] : _owner (address): 0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000004e64c2d06d19d13061e62e291b2c4e9fe5679b93


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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