ETH Price: $2,642.08 (-0.35%)

Contract

0xEaB64B2320A1Fc1e65f4C7253385ec18e4B4313B
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Execute Swap87113892019-10-10 2:34:121836 days ago1570674852IN
0xEaB64B23...8e4B4313B
0 ETH0.0003331111
Execute Swap87113892019-10-10 2:34:121836 days ago1570674852IN
0xEaB64B23...8e4B4313B
0 ETH0.0004981111
Create Swap87113852019-10-10 2:32:311836 days ago1570674751IN
0xEaB64B23...8e4B4313B
0 ETH0.0011704211
Create Swap87113852019-10-10 2:32:311836 days ago1570674751IN
0xEaB64B23...8e4B4313B
0 ETH0.0013354211
Execute Swap87113812019-10-10 2:31:381836 days ago1570674698IN
0xEaB64B23...8e4B4313B
0 ETH0.0003612711
Create Swap87113782019-10-10 2:30:341836 days ago1570674634IN
0xEaB64B23...8e4B4313B
0 ETH0.0013635811
Execute Swap87107682019-10-10 0:07:301836 days ago1570666050IN
0xEaB64B23...8e4B4313B
0 ETH0.000295589
Create Swap87107652019-10-10 0:06:291836 days ago1570665989IN
0xEaB64B23...8e4B4313B
0 ETH0.00111459
Execute Swap87107572019-10-10 0:04:391836 days ago1570665879IN
0xEaB64B23...8e4B4313B
0 ETH0.000295589
Create Swap87107552019-10-10 0:04:221836 days ago1570665862IN
0xEaB64B23...8e4B4313B
0 ETH0.001115659
Execute Swap87104762019-10-09 22:59:531836 days ago1570661993IN
0xEaB64B23...8e4B4313B
0 ETH0.000272549
Execute Swap87104742019-10-09 22:59:241836 days ago1570661964IN
0xEaB64B23...8e4B4313B
0 ETH0.000408129
Create Swap87104702019-10-09 22:59:161836 days ago1570661956IN
0xEaB64B23...8e4B4313B
0 ETH0.000957619
Create Swap87104682019-10-09 22:58:591836 days ago1570661939IN
0xEaB64B23...8e4B4313B
0 ETH0.001093199
Execute Swap87095832019-10-09 19:41:131837 days ago1570650073IN
0xEaB64B23...8e4B4313B
0 ETH0.000608669
Create Swap87095752019-10-09 19:39:551837 days ago1570649995IN
0xEaB64B23...8e4B4313B
0 ETH0.0015840513
Execute Swap87092822019-10-09 18:35:121837 days ago1570646112IN
0xEaB64B23...8e4B4313B
0 ETH0.000272549
Create Swap87092792019-10-09 18:34:111837 days ago1570646051IN
0xEaB64B23...8e4B4313B
0 ETH0.001092619
Execute Swap87092642019-10-09 18:30:441837 days ago1570645844IN
0xEaB64B23...8e4B4313B
0 ETH0.000608089
Create Swap87092582019-10-09 18:29:361837 days ago1570645776IN
0xEaB64B23...8e4B4313B
0 ETH0.001096079
Execute Swap87092282019-10-09 18:23:461837 days ago1570645426IN
0xEaB64B23...8e4B4313B
0 ETH0.000473089
Create Swap87092232019-10-09 18:21:261837 days ago1570645286IN
0xEaB64B23...8e4B4313B
0 ETH0.001095499
Execute Swap87092232019-10-09 18:21:261837 days ago1570645286IN
0xEaB64B23...8e4B4313B
0 ETH0.000273129
Execute Swap87092232019-10-09 18:21:261837 days ago1570645286IN
0xEaB64B23...8e4B4313B
0 ETH0.000407549
Create Swap87092192019-10-09 18:21:071837 days ago1570645267IN
0xEaB64B23...8e4B4313B
0 ETH0.000958199
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AtomicBroker

Compiler Version
v0.4.25+commit.59dbf8f1

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2019-04-05
*/

// File: openzeppelin-solidity/contracts/math/SafeMath.sol

pragma solidity ^0.4.24;


/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
    // Gas optimization: this is cheaper than asserting 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (_a == 0) {
      return 0;
    }

    c = _a * _b;
    assert(c / _a == _b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
    // assert(_b > 0); // Solidity automatically throws when dividing by 0
    // uint256 c = _a / _b;
    // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
    return _a / _b;
  }

  /**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
    assert(_b <= _a);
    return _a - _b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
    c = _a + _b;
    assert(c >= _a);
    return c;
  }
}

// File: openzeppelin-solidity/contracts/ownership/Ownable.sol

pragma solidity ^0.4.24;


/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;


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


  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  constructor() public {
    owner = msg.sender;
  }

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

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   * @notice Renouncing to ownership will leave the contract without an owner.
   * It will not be possible to call the functions with the `onlyOwner`
   * modifier anymore.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(owner);
    owner = address(0);
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param _newOwner The address to transfer ownership to.
   */
  function transferOwnership(address _newOwner) public onlyOwner {
    _transferOwnership(_newOwner);
  }

  /**
   * @dev Transfers control of the contract to a newOwner.
   * @param _newOwner The address to transfer ownership to.
   */
  function _transferOwnership(address _newOwner) internal {
    require(_newOwner != address(0));
    emit OwnershipTransferred(owner, _newOwner);
    owner = _newOwner;
  }
}

// File: openzeppelin-solidity/contracts/ownership/Claimable.sol

pragma solidity ^0.4.24;



/**
 * @title Claimable
 * @dev Extension for the Ownable contract, where the ownership needs to be claimed.
 * This allows the new owner to accept the transfer.
 */
contract Claimable is Ownable {
  address public pendingOwner;

  /**
   * @dev Modifier throws if called by any account other than the pendingOwner.
   */
  modifier onlyPendingOwner() {
    require(msg.sender == pendingOwner);
    _;
  }

  /**
   * @dev Allows the current owner to set the pendingOwner address.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    pendingOwner = newOwner;
  }

  /**
   * @dev Allows the pendingOwner address to finalize the transfer.
   */
  function claimOwnership() public onlyPendingOwner {
    emit OwnershipTransferred(owner, pendingOwner);
    owner = pendingOwner;
    pendingOwner = address(0);
  }
}

// File: contracts/Broker.sol

pragma solidity 0.4.25;



/// @title The Broker + Vault contract for Switcheo Exchange
/// @author Switcheo Network
/// @notice This contract faciliates Ethereum and ERC-20 trades
/// between users. Users can trade with each other by making
/// and taking offers without giving up custody of their tokens.
/// Users should first deposit tokens, then communicate off-chain
/// with the exchange coordinator, in order to place orders
/// (make / take offers). This allows trades to be confirmed
/// immediately by the coordinator, and settled on-chain through
/// this contract at a later time.
contract Broker is Claimable {
    using SafeMath for uint256;

    struct Offer {
        address maker;
        address offerAsset;
        address wantAsset;
        uint64 nonce;
        uint256 offerAmount;
        uint256 wantAmount;
        uint256 availableAmount; // the remaining offer amount
    }

    struct AnnouncedWithdrawal {
        uint256 amount;
        uint256 canWithdrawAt;
    }

    // Exchange states
    enum State { Active, Inactive }
    State public state;

    // The maximum announce delay in seconds
    // (7 days * 24 hours * 60 mins * 60 seconds)
    uint32 constant maxAnnounceDelay = 604800;
    // Ether token "address" is set as the constant 0x00
    address constant etherAddr = address(0);

    // deposits
    uint8 constant ReasonDeposit = 0x01;
    // making an offer
    uint8 constant ReasonMakerGive = 0x02;
    uint8 constant ReasonMakerFeeGive = 0x10;
    uint8 constant ReasonMakerFeeReceive = 0x11;
    // filling an offer
    uint8 constant ReasonFillerGive = 0x03;
    uint8 constant ReasonFillerFeeGive = 0x04;
    uint8 constant ReasonFillerReceive = 0x05;
    uint8 constant ReasonMakerReceive = 0x06;
    uint8 constant ReasonFillerFeeReceive = 0x07;
    // cancelling an offer
    uint8 constant ReasonCancel = 0x08;
    uint8 constant ReasonCancelFeeGive = 0x12;
    uint8 constant ReasonCancelFeeReceive = 0x13;
    // withdrawals
    uint8 constant ReasonWithdraw = 0x09;
    uint8 constant ReasonWithdrawFeeGive = 0x14;
    uint8 constant ReasonWithdrawFeeReceive = 0x15;

    // The coordinator sends trades (balance transitions) to the exchange
    address public coordinator;
    // The operator receives fees
    address public operator;
    // The time required to wait after a cancellation is announced
    // to let the operator detect it in non-byzantine conditions
    uint32 public cancelAnnounceDelay;
    // The time required to wait after a withdrawal is announced
    // to let the operator detect it in non-byzantine conditions
    uint32 public withdrawAnnounceDelay;

    // User balances by: userAddress => assetHash => balance
    mapping(address => mapping(address => uint256)) public balances;
    // Offers by the creation transaction hash: transactionHash => offer
    mapping(bytes32 => Offer) public offers;
    // A record of which hashes have been used before
    mapping(bytes32 => bool) public usedHashes;
    // Set of whitelisted spender addresses allowed by the owner
    mapping(address => bool) public whitelistedSpenders;
    // Spenders which have been approved by individual user as: userAddress => spenderAddress => true
    mapping(address => mapping(address => bool)) public approvedSpenders;
    // Announced withdrawals by: userAddress => assetHash => data
    mapping(address => mapping(address => AnnouncedWithdrawal)) public announcedWithdrawals;
    // Announced cancellations by: offerHash => data
    mapping(bytes32 => uint256) public announcedCancellations;

    // Emitted when new offers made
    event Make(address indexed maker, bytes32 indexed offerHash);
    // Emitted when offers are filled
    event Fill(address indexed filler, bytes32 indexed offerHash, uint256 amountFilled, uint256 amountTaken, address indexed maker);
    // Emitted when offers are cancelled
    event Cancel(address indexed maker, bytes32 indexed offerHash);
    // Emitted on any balance state transition (+ve)
    event BalanceIncrease(address indexed user, address indexed token, uint256 amount, uint8 indexed reason);
    // Emitted on any balance state transition (-ve)
    event BalanceDecrease(address indexed user, address indexed token, uint256 amount, uint8 indexed reason);
    // Emitted when a withdrawal is annnounced
    event WithdrawAnnounce(address indexed user, address indexed token, uint256 amount, uint256 canWithdrawAt);
    // Emitted when a cancellation is annnounced
    event CancelAnnounce(address indexed user, bytes32 indexed offerHash, uint256 canCancelAt);
    // Emitted when a user approved a spender
    event SpenderApprove(address indexed user, address indexed spender);
    // Emitted when a user rescinds approval for a spender
    event SpenderRescind(address indexed user, address indexed spender);

    /// @notice Initializes the Broker contract
    /// @dev The coordinator and operator is initialized
    /// to be the address of the sender. The Broker is immediately
    /// put into an active state, with maximum exit delays set.
    constructor()
        public
    {
        coordinator = msg.sender;
        operator = msg.sender;
        cancelAnnounceDelay = maxAnnounceDelay;
        withdrawAnnounceDelay = maxAnnounceDelay;
        state = State.Active;
    }

    modifier onlyCoordinator() {
        require(
            msg.sender == coordinator,
            "Invalid sender"
        );
        _;
    }

    modifier onlyActiveState() {
        require(
            state == State.Active,
            "Invalid state"
        );
        _;
    }

    modifier onlyInactiveState() {
        require(
            state == State.Inactive,
            "Invalid state"
        );
        _;
    }

    modifier notMoreThanMaxDelay(uint32 _delay) {
        require(
            _delay <= maxAnnounceDelay,
            "Invalid delay"
        );
        _;
    }

    modifier unusedReasonCode(uint8 _reasonCode) {
        require(
            _reasonCode > ReasonWithdrawFeeReceive,
            "Invalid reason code"
        );
        _;
    }

    /// @notice Sets the Broker contract state
    /// @dev There are only two states - Active & Inactive.
    ///
    /// The Active state is the normal operating state for the contract -
    /// deposits, trading and withdrawals can be carried out.
    ///
    /// In the Inactive state, the coordinator can invoke additional
    /// emergency methods such as emergencyCancel and emergencyWithdraw,
    /// without the cooperation of users. However, deposits and trading
    /// methods cannot be invoked at that time. This state is meant
    /// primarily to terminate and upgrade the contract, or to be used
    /// in the event that the contract is considered no longer viable
    /// to continue operation, and held tokens should be immediately
    /// withdrawn to their respective owners.
    /// @param _state The state to transition the contract into
    function setState(State _state) external onlyOwner { state = _state; }

    /// @notice Sets the coordinator address.
    /// @dev All standard operations (except `depositEther`)
    /// must be invoked by the coordinator.
    /// @param _coordinator The address to set as the coordinator
    function setCoordinator(address _coordinator) external onlyOwner {
        _validateAddress(_coordinator);
        coordinator = _coordinator;
    }

    /// @notice Sets the operator address.
    /// @dev All fees are paid to the operator.
    /// @param _operator The address to set as the operator
    function setOperator(address _operator) external onlyOwner {
        _validateAddress(operator);
        operator = _operator;
    }

    /// @notice Sets the delay between when a cancel
    /// intention must be announced, and when the cancellation
    /// can actually be executed on-chain
    /// @dev This delay exists so that the coordinator has time to
    /// respond when a user is attempting to bypass it and cancel
    /// offers directly on-chain.
    /// Note that this is an direct on-chain cancellation
    /// is an atypical operation - see `slowCancel`
    /// for more details.
    /// @param _delay The delay in seconds
    function setCancelAnnounceDelay(uint32 _delay)
        external
        onlyOwner
        notMoreThanMaxDelay(_delay)
    {
        cancelAnnounceDelay = _delay;
    }

    /// @notice Sets the delay (in seconds) between when a withdrawal
    /// intention must be announced, and when the withdrawal
    /// can actually be executed on-chain.
    /// @dev This delay exists so that the coordinator has time to
    /// respond when a user is attempting to bypass it and cancel
    /// offers directly on-chain. See `announceWithdraw` and
    /// `slowWithdraw` for more details.
    /// @param _delay The delay in seconds
    function setWithdrawAnnounceDelay(uint32 _delay)
        external
        onlyOwner
        notMoreThanMaxDelay(_delay)
    {
        withdrawAnnounceDelay = _delay;
    }

    /// @notice Adds an address to the set of allowed spenders.
    /// @dev Spenders are meant to be additional EVM contracts that
    /// will allow adding or upgrading of trading functionality, without
    /// having to cancel all offers and withdraw all tokens for all users.
    /// This whitelist ensures that all approved spenders are contracts
    /// that have been verified by the owner. Note that each user also
    /// has to invoke `approveSpender` to actually allow the `_spender`
    /// to spend his/her balance, so that they can examine / verify
    /// the new spender contract first.
    /// @param _spender The address to add as a whitelisted spender
    function addSpender(address _spender)
        external
        onlyOwner
    {
        _validateAddress(_spender);
        whitelistedSpenders[_spender] = true;
    }

    /// @notice Removes an address from the set of allowed spenders.
    /// @dev Note that removing a spender from the whitelist will not
    /// prevent already approved spenders from spending a user's balance.
    /// This is to ensure that the spender contracts can be certain that once
    /// an approval is done, the owner cannot rescient spending priviledges,
    /// and cause tokens to be withheld or locked in the spender contract.
    /// Users must instead manually rescind approvals using `rescindApproval`
    /// after the `_spender` has been removed from the whitelist.
    /// @param _spender The address to remove as a whitelisted spender
    function removeSpender(address _spender)
        external
        onlyOwner
    {
        _validateAddress(_spender);
        delete whitelistedSpenders[_spender];
    }

    /// @notice Deposits Ethereum tokens under the `msg.sender`'s balance
    /// @dev Allows sending ETH to the contract, and increasing
    /// the user's contract balance by the amount sent in.
    /// This operation is only usable in an Active state to prevent
    /// a terminated contract from receiving tokens.
    function depositEther()
        external
        payable
        onlyActiveState
    {
        require(
            msg.value > 0,
            'Invalid value'
        );
        balances[msg.sender][etherAddr] = balances[msg.sender][etherAddr].add(msg.value);
        emit BalanceIncrease(msg.sender, etherAddr, msg.value, ReasonDeposit);
    }

    /// @notice Deposits ERC20 tokens under the `_user`'s balance
    /// @dev Allows sending ERC20 tokens to the contract, and increasing
    /// the user's contract balance by the amount sent in. This operation
    /// can only be used after an ERC20 `approve` operation for a
    /// sufficient amount has been carried out.
    ///
    /// Note that this operation does not require user signatures as
    /// a valid ERC20 `approve` call is considered as intent to deposit
    /// the tokens. This is as there is no other ERC20 methods that this
    /// contract can call.
    ///
    /// This operation can only be called by the coordinator,
    /// and should be autoamtically done so whenever an `approve` event
    /// from a ERC20 token (that the coordinator deems valid)
    /// approving this contract to spend tokens on behalf of a user is seen.
    ///
    /// This operation is only usable in an Active state to prevent
    /// a terminated contract from receiving tokens.
    /// @param _user The address of the user that is depositing tokens
    /// @param _token The address of the ERC20 token to deposit
    /// @param _amount The (approved) amount to deposit
    function depositERC20(
        address _user,
        address _token,
        uint256 _amount
    )
        external
        onlyCoordinator
        onlyActiveState
    {
        require(
            _amount > 0,
            'Invalid value'
        );
        balances[_user][_token] = balances[_user][_token].add(_amount);

        _validateIsContract(_token);
        require(
            _token.call(
                bytes4(keccak256("transferFrom(address,address,uint256)")),
                _user,
                address(this),
                _amount
            ),
            "transferFrom call failed"
        );
        require(
            _getSanitizedReturnValue(),
            "transferFrom failed."
        );

        emit BalanceIncrease(_user, _token, _amount, ReasonDeposit);
    }

    /// @notice Withdraws `_amount` worth of `_token`s to the `_withdrawer`
    /// @dev This is the standard withdraw operation. Tokens can only be
    /// withdrawn directly to the token balance owner's address.
    /// Fees can be paid to cover network costs, as the operation must
    /// be invoked by the coordinator. The hash of all parameters, prefixed
    /// with the operation name "withdraw" must be signed by the withdrawer
    /// to validate the withdrawal request. A nonce that is issued by the
    /// coordinator is used to prevent replay attacks.
    /// See `slowWithdraw` for withdrawing without requiring the coordinator's
    /// involvement.
    /// @param _withdrawer The address of the user that is withdrawing tokens
    /// @param _token The address of the token to withdraw
    /// @param _amount The number of tokens to withdraw
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _nonce The nonce to prevent replay attacks
    /// @param _v The `v` component of the `_withdrawer`'s signature
    /// @param _r The `r` component of the `_withdrawer`'s signature
    /// @param _s The `s` component of the `_withdrawer`'s signature
    function withdraw(
        address _withdrawer,
        address _token,
        uint256 _amount,
        address _feeAsset,
        uint256 _feeAmount,
        uint64 _nonce,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    )
        external
        onlyCoordinator
    {
        bytes32 msgHash = keccak256(abi.encodePacked(
            "withdraw",
            _withdrawer,
            _token,
            _amount,
            _feeAsset,
            _feeAmount,
            _nonce
        ));

        require(
            _recoverAddress(msgHash, _v, _r, _s) == _withdrawer,
            "Invalid signature"
        );

        _validateAndAddHash(msgHash);

        _withdraw(_withdrawer, _token, _amount, _feeAsset, _feeAmount);
    }

    /// @notice Announces intent to withdraw tokens using `slowWithdraw`
    /// @dev Allows a user to invoke `slowWithdraw` after a minimum of
    /// `withdrawAnnounceDelay` seconds has passed.
    /// This announcement and delay is necessary so that the operator has time
    /// to respond if a user attempts to invoke a `slowWithdraw` even though
    /// the exchange is operating normally. In that case, the coordinator would respond
    /// by not allowing the announced amount of tokens to be used in future trades
    /// the moment a `WithdrawAnnounce` is seen.
    /// @param _token The address of the token to withdraw after the required exit delay
    /// @param _amount The number of tokens to withdraw after the required exit delay
    function announceWithdraw(
        address _token,
        uint256 _amount
    )
        external
    {
        require(
            _amount <= balances[msg.sender][_token],
            "Amount too high"
        );

        AnnouncedWithdrawal storage announcement = announcedWithdrawals[msg.sender][_token];
        uint256 canWithdrawAt = now + withdrawAnnounceDelay;

        announcement.canWithdrawAt = canWithdrawAt;
        announcement.amount = _amount;

        emit WithdrawAnnounce(msg.sender, _token, _amount, canWithdrawAt);
    }

    /// @notice Withdraw tokens without requiring the coordinator
    /// @dev This operation is meant to be used if the operator becomes "byzantine",
    /// so that users can still exit tokens locked in this contract.
    /// The `announceWithdraw` operation has to be invoked first, and a minimum time of
    /// `withdrawAnnounceDelay` seconds have to pass, before this operation can be carried out.
    /// Note that this direct on-chain withdrawal is an atypical operation, and
    /// the normal `withdraw` operation should be used in non-byzantine states.
    /// @param _withdrawer The address of the user that is withdrawing tokens
    /// @param _token The address of the token to withdraw
    /// @param _amount The number of tokens to withdraw
    function slowWithdraw(
        address _withdrawer,
        address _token,
        uint256 _amount
    )
        external
    {
        AnnouncedWithdrawal memory announcement = announcedWithdrawals[_withdrawer][_token];

        require(
            announcement.canWithdrawAt != 0 && announcement.canWithdrawAt <= now,
            "Insufficient delay"
        );

        require(
            announcement.amount == _amount,
            "Invalid amount"
        );

        delete announcedWithdrawals[_withdrawer][_token];

        _withdraw(_withdrawer, _token, _amount, etherAddr, 0);
    }

    /// @notice Withdraws tokens to the owner without requiring the owner's signature
    /// @dev Can only be invoked in an Inactive state by the coordinator.
    /// This operation is meant to be used in emergencies only.
    /// @param _withdrawer The address of the user that should have tokens withdrawn
    /// @param _token The address of the token to withdraw
    /// @param _amount The number of tokens to withdraw
    function emergencyWithdraw(
        address _withdrawer,
        address _token,
        uint256 _amount
    )
        external
        onlyCoordinator
        onlyInactiveState
    {
        _withdraw(_withdrawer, _token, _amount, etherAddr, 0);
    }

    /// @notice Makes an offer which can be filled by other users.
    /// @dev Makes an offer for `_offerAmount` of `offerAsset` tokens
    /// for `wantAmount` of `wantAsset` tokens, that can be filled later
    /// by one or more counterparties using `fillOffer` or `fillOffers`.
    /// The offer can be later cancelled using `cancel` or `slowCancel` as long
    /// as it has not completely been filled.
    /// A fee of `_feeAmount` of `_feeAsset` tokens can be paid to the operator
    /// to cover orderbook maintenance and network costs.
    /// The hash of all parameters, prefixed with the operation name "makeOffer"
    /// must be signed by the `_maker` to validate the offer request.
    /// A nonce that is issued by the coordinator is used to prevent replay attacks.
    /// This operation can only be invoked by the coordinator in an Active state.
    /// @param _maker The address of the user that is making the offer
    /// @param _offerAsset The address of the token being offered
    /// @param _wantAsset The address of the token asked in return
    /// @param _offerAmount The number of tokens being offered
    /// @param _wantAmount The number of tokens asked for in return
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _nonce The nonce to prevent replay attacks
    /// @param _v The `v` component of the `_maker`'s signature
    /// @param _r The `r` component of the `_maker`'s signature
    /// @param _s The `s` component of the `_maker`'s signature
    function makeOffer(
        address _maker,
        address _offerAsset,
        address _wantAsset,
        uint256 _offerAmount,
        uint256 _wantAmount,
        address _feeAsset,
        uint256 _feeAmount,
        uint64 _nonce,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    )
        external
        onlyCoordinator
        onlyActiveState
    {
        require(
            _offerAmount > 0 && _wantAmount > 0,
            "Invalid amounts"
        );

        require(
            _offerAsset != _wantAsset,
            "Invalid assets"
        );

        bytes32 offerHash = keccak256(abi.encodePacked(
            "makeOffer",
            _maker,
            _offerAsset,
            _wantAsset,
            _offerAmount,
            _wantAmount,
            _feeAsset,
            _feeAmount,
            _nonce
        ));

        require(
            _recoverAddress(offerHash, _v, _r, _s) == _maker,
            "Invalid signature"
        );

        _validateAndAddHash(offerHash);

        // Reduce maker's balance
        _decreaseBalanceAndPayFees(
            _maker,
            _offerAsset,
            _offerAmount,
            _feeAsset,
            _feeAmount,
            ReasonMakerGive,
            ReasonMakerFeeGive,
            ReasonMakerFeeReceive
        );

        // Store the offer
        Offer storage offer = offers[offerHash];
        offer.maker = _maker;
        offer.offerAsset = _offerAsset;
        offer.wantAsset = _wantAsset;
        offer.offerAmount = _offerAmount;
        offer.wantAmount = _wantAmount;
        offer.availableAmount = _offerAmount;
        offer.nonce = _nonce;

        emit Make(_maker, offerHash);
    }

    /// @notice Fills a offer that has been previously made using `makeOffer`.
    /// @dev Fill an offer with `_offerHash` by giving `_amountToTake` of
    /// the offers' `wantAsset` tokens.
    /// A fee of `_feeAmount` of `_feeAsset` tokens can be paid to the operator
    /// to cover orderbook maintenance and network costs.
    /// The hash of all parameters, prefixed with the operation name "fillOffer"
    /// must be signed by the `_filler` to validate the fill request.
    /// A nonce that is issued by the coordinator is used to prevent replay attacks.
    /// This operation can only be invoked by the coordinator in an Active state.
    /// @param _filler The address of the user that is filling the offer
    /// @param _offerHash The hash of the offer to fill
    /// @param _amountToTake The number of tokens to take from the offer
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _nonce The nonce to prevent replay attacks
    /// @param _v The `v` component of the `_filler`'s signature
    /// @param _r The `r` component of the `_filler`'s signature
    /// @param _s The `s` component of the `_filler`'s signature
    function fillOffer(
        address _filler,
        bytes32 _offerHash,
        uint256 _amountToTake,
        address _feeAsset,
        uint256 _feeAmount,
        uint64 _nonce,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    )
        external
        onlyCoordinator
        onlyActiveState
    {
        bytes32 msgHash = keccak256(
            abi.encodePacked(
                "fillOffer",
                _filler,
                _offerHash,
                _amountToTake,
                _feeAsset,
                _feeAmount,
                _nonce
            )
        );

        require(
            _recoverAddress(msgHash, _v, _r, _s) == _filler,
            "Invalid signature"
        );

        _validateAndAddHash(msgHash);

        _fill(_filler, _offerHash, _amountToTake, _feeAsset, _feeAmount);
    }

    /// @notice Fills multiple offers that have been previously made using `makeOffer`.
    /// @dev Fills multiple offers with hashes in `_offerHashes` for amounts in
    /// `_amountsToTake`. This method allows conserving of the base gas cost.
    /// A fee of `_feeAmount` of `_feeAsset`  tokens can be paid to the operator
    /// to cover orderbook maintenance and network costs.
    /// The hash of all parameters, prefixed with the operation name "fillOffers"
    /// must be signed by the maker to validate the fill request.
    /// A nonce that is issued by the coordinator is used to prevent replay attacks.
    /// This operation can only be invoked by the coordinator in an Active state.
    /// @param _filler The address of the user that is filling the offer
    /// @param _offerHashes The hashes of the offers to fill
    /// @param _amountsToTake The number of tokens to take for each offer
    /// (each index corresponds to the entry with the same index in _offerHashes)
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _nonce The nonce to prevent replay attacks
    /// @param _v The `v` component of the `_filler`'s signature
    /// @param _r The `r` component of the `_filler`'s signature
    /// @param _s The `s` component of the `_filler`'s signature
    function fillOffers(
        address _filler,
        bytes32[] _offerHashes,
        uint256[] _amountsToTake,
        address _feeAsset,
        uint256 _feeAmount,
        uint64 _nonce,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    )
        external
        onlyCoordinator
        onlyActiveState
    {
        require(
            _offerHashes.length > 0,
            'Invalid input'
        );
        require(
            _offerHashes.length == _amountsToTake.length,
            'Invalid inputs'
        );

        bytes32 msgHash = keccak256(
            abi.encodePacked(
                "fillOffers",
                _filler,
                _offerHashes,
                _amountsToTake,
                _feeAsset,
                _feeAmount,
                _nonce
            )
        );

        require(
            _recoverAddress(msgHash, _v, _r, _s) == _filler,
            "Invalid signature"
        );

        _validateAndAddHash(msgHash);

        for (uint32 i = 0; i < _offerHashes.length; i++) {
            _fill(_filler, _offerHashes[i], _amountsToTake[i], etherAddr, 0);
        }

        _paySeparateFees(
            _filler,
            _feeAsset,
            _feeAmount,
            ReasonFillerFeeGive,
            ReasonFillerFeeReceive
        );
    }

    /// @notice Cancels an offer that was preivously made using `makeOffer`.
    /// @dev Cancels the offer with `_offerHash`. An `_expectedAvailableAmount`
    /// is provided to allow the coordinator to ensure that the offer is not accidentally
    /// cancelled ahead of time (where there is a pending fill that has not been settled).
    /// The hash of the _offerHash, _feeAsset, `_feeAmount` prefixed with the
    /// operation name "cancel" must be signed by the offer maker to validate
    /// the cancellation request. Only the coordinator can invoke this operation.
    /// See `slowCancel` for cancellation without requiring the coordinator's
    /// involvement.
    /// @param _offerHash The hash of the offer to cancel
    /// @param _expectedAvailableAmount The number of tokens that should be present when cancelling
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _v The `v` component of the offer maker's signature
    /// @param _r The `r` component of the offer maker's signature
    /// @param _s The `s` component of the offer maker's signature
    function cancel(
        bytes32 _offerHash,
        uint256 _expectedAvailableAmount,
        address _feeAsset,
        uint256 _feeAmount,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    )
        external
        onlyCoordinator
    {
        require(
            _recoverAddress(keccak256(abi.encodePacked(
                "cancel",
                _offerHash,
                _feeAsset,
                _feeAmount
            )), _v, _r, _s) == offers[_offerHash].maker,
            "Invalid signature"
        );

        _cancel(_offerHash, _expectedAvailableAmount, _feeAsset, _feeAmount);
    }

    /// @notice Announces intent to cancel tokens using `slowCancel`
    /// @dev Allows a user to invoke `slowCancel` after a minimum of
    /// `cancelAnnounceDelay` seconds has passed.
    /// This announcement and delay is necessary so that the operator has time
    /// to respond if a user attempts to invoke a `slowCancel` even though
    /// the exchange is operating normally.
    /// In that case, the coordinator would simply stop matching the offer to
    /// viable counterparties the moment the `CancelAnnounce` is seen.
    /// @param _offerHash The hash of the offer that will be cancelled
    function announceCancel(bytes32 _offerHash)
        external
    {
        Offer memory offer = offers[_offerHash];

        require(
            offer.maker == msg.sender,
            "Invalid sender"
        );

        require(
            offer.availableAmount > 0,
            "Offer already cancelled"
        );

        uint256 canCancelAt = now + cancelAnnounceDelay;
        announcedCancellations[_offerHash] = canCancelAt;

        emit CancelAnnounce(offer.maker, _offerHash, canCancelAt);
    }

    /// @notice Cancel an offer without requiring the coordinator
    /// @dev This operation is meant to be used if the operator becomes "byzantine",
    /// so that users can still cancel offers in this contract, and withdraw tokens
    /// using `slowWithdraw`.
    /// The `announceCancel` operation has to be invoked first, and a minimum time of
    /// `cancelAnnounceDelay` seconds have to pass, before this operation can be carried out.
    /// Note that this direct on-chain cancellation is an atypical operation, and
    /// the normal `cancel` operation should be used in non-byzantine states.
    /// @param _offerHash The hash of the offer to cancel
    function slowCancel(bytes32 _offerHash)
        external
    {
        require(
            announcedCancellations[_offerHash] != 0 && announcedCancellations[_offerHash] <= now,
            "Insufficient delay"
        );

        delete announcedCancellations[_offerHash];

        Offer memory offer = offers[_offerHash];
        _cancel(_offerHash, offer.availableAmount, etherAddr, 0);
    }

    /// @notice Cancels an offer immediately once cancellation intent
    /// has been announced.
    /// @dev Can only be invoked by the coordinator. This allows
    /// the coordinator to quickly remove offers that it has already
    /// acknowledged, and move its offer book into a consistent state.
    function fastCancel(bytes32 _offerHash, uint256 _expectedAvailableAmount)
        external
        onlyCoordinator
    {
        require(
            announcedCancellations[_offerHash] != 0,
            "Missing annoncement"
        );

        delete announcedCancellations[_offerHash];

        _cancel(_offerHash, _expectedAvailableAmount, etherAddr, 0);
    }

    /// @notice Cancels an offer without requiring the owner's signature,
    /// so that the tokens can be withdrawn using `emergencyWithdraw`.
    /// @dev Can only be invoked in an Inactive state by the coordinator.
    /// This operation is meant to be used in emergencies only.
    function emergencyCancel(bytes32 _offerHash, uint256 _expectedAvailableAmount)
        external
        onlyCoordinator
        onlyInactiveState
    {
        _cancel(_offerHash, _expectedAvailableAmount, etherAddr, 0);
    }

    /// @notice Approve an address for spending any amount of
    /// any token from the `msg.sender`'s balances
    /// @dev Analogous to ERC-20 `approve`, with the following differences:
    ///     - `_spender` must be whitelisted by owner
    ///     - approval can be rescinded at a later time by the user
    ///       iff it has been removed from the whitelist
    ///     - spending amount is unlimited
    /// @param _spender The address to approve spending
    function approveSpender(address _spender)
        external
    {
        require(
            whitelistedSpenders[_spender],
            "Spender is not whitelisted"
        );

        approvedSpenders[msg.sender][_spender] = true;
        emit SpenderApprove(msg.sender, _spender);
    }

    /// @notice Rescinds a previous approval for spending the `msg.sender`'s contract balance.
    /// @dev Rescinds approval for a spender, after it has been removed from
    /// the `whitelistedSpenders` set. This allows an approval to be removed
    /// if both the owner and user agrees that the previously approved spender
    /// contract should no longer be used.
    /// @param _spender The address to rescind spending approval
    function rescindApproval(address _spender)
        external
    {
        require(
            approvedSpenders[msg.sender][_spender],
            "Spender has not been approved"
        );

        require(
            whitelistedSpenders[_spender] != true,
            "Spender must be removed from the whitelist"
        );

        delete approvedSpenders[msg.sender][_spender];
        emit SpenderRescind(msg.sender, _spender);
    }

    /// @notice Transfers tokens from one address to another
    /// @dev Analogous to ERC-20 `transferFrom`, with the following differences:
    ///     - the address of the token to transfer must be specified
    ///     - any amount of token can be transferred, as long as it is less or equal
    ///       to `_from`'s balance
    ///     - reason codes can be attached and they must not use reasons specified in
    ///       this contract
    /// @param _from The address to transfer tokens from
    /// @param _to The address to transfer tokens to
    /// @param _amount The number of tokens to transfer
    /// @param _token The address of the token to transfer
    /// @param _decreaseReason A reason code to emit in the `BalanceDecrease` event
    /// @param _increaseReason A reason code to emit in the `BalanceIncrease` event
    function spendFrom(
        address _from,
        address _to,
        uint256 _amount,
        address _token,
        uint8 _decreaseReason,
        uint8 _increaseReason
    )
        external
        unusedReasonCode(_decreaseReason)
        unusedReasonCode(_increaseReason)
    {
        require(
            approvedSpenders[_from][msg.sender],
            "Spender has not been approved"
        );

        _validateAddress(_to);

        balances[_from][_token] = balances[_from][_token].sub(_amount);
        emit BalanceDecrease(_from, _token, _amount, _decreaseReason);

        balances[_to][_token] = balances[_to][_token].add(_amount);
        emit BalanceIncrease(_to, _token, _amount, _increaseReason);
    }

    /// @dev Overrides ability to renounce ownership as this contract is
    /// meant to always have an owner.
    function renounceOwnership() public { require(false, "Cannot have no owner"); }

    /// @dev The actual withdraw logic that is used internally by multiple operations.
    function _withdraw(
        address _withdrawer,
        address _token,
        uint256 _amount,
        address _feeAsset,
        uint256 _feeAmount
    )
        private
    {
        // SafeMath.sub checks that balance is sufficient already
        _decreaseBalanceAndPayFees(
            _withdrawer,
            _token,
            _amount,
            _feeAsset,
            _feeAmount,
            ReasonWithdraw,
            ReasonWithdrawFeeGive,
            ReasonWithdrawFeeReceive
        );

        if (_token == etherAddr) // ether
        {
            _withdrawer.transfer(_amount);
        }
        else
        {
            _validateIsContract(_token);
            require(
                _token.call(
                    bytes4(keccak256("transfer(address,uint256)")), _withdrawer, _amount
                ),
                "transfer call failed"
            );
            require(
                _getSanitizedReturnValue(),
                "transfer failed"
            );
        }
    }

    /// @dev The actual fill logic that is used internally by multiple operations.
    function _fill(
        address _filler,
        bytes32 _offerHash,
        uint256 _amountToTake,
        address _feeAsset,
        uint256 _feeAmount
    )
        private
    {
        require(
            _amountToTake > 0,
            "Invalid input"
        );

        Offer storage offer = offers[_offerHash];
        require(
            offer.maker != _filler,
            "Invalid filler"
        );

        require(
            offer.availableAmount != 0,
            "Offer already filled"
        );

        uint256 amountToFill = (_amountToTake.mul(offer.wantAmount)).div(offer.offerAmount);

        // transfer amountToFill in fillAsset from filler to maker
        balances[_filler][offer.wantAsset] = balances[_filler][offer.wantAsset].sub(amountToFill);
        emit BalanceDecrease(_filler, offer.wantAsset, amountToFill, ReasonFillerGive);

        balances[offer.maker][offer.wantAsset] = balances[offer.maker][offer.wantAsset].add(amountToFill);
        emit BalanceIncrease(offer.maker, offer.wantAsset, amountToFill, ReasonMakerReceive);

        // deduct amountToTake in takeAsset from offer
        offer.availableAmount = offer.availableAmount.sub(_amountToTake);
        _increaseBalanceAndPayFees(
            _filler,
            offer.offerAsset,
            _amountToTake,
            _feeAsset,
            _feeAmount,
            ReasonFillerReceive,
            ReasonFillerFeeGive,
            ReasonFillerFeeReceive
        );
        emit Fill(_filler, _offerHash, amountToFill, _amountToTake, offer.maker);

        if (offer.availableAmount == 0)
        {
            delete offers[_offerHash];
        }
    }

    /// @dev The actual cancellation logic that is used internally by multiple operations.
    function _cancel(
        bytes32 _offerHash,
        uint256 _expectedAvailableAmount,
        address _feeAsset,
        uint256 _feeAmount
    )
        private
    {
        Offer memory offer = offers[_offerHash];

        require(
            offer.availableAmount > 0,
            "Offer already cancelled"
        );

        require(
            offer.availableAmount == _expectedAvailableAmount,
            "Invalid input"
        );

        delete offers[_offerHash];

        _increaseBalanceAndPayFees(
            offer.maker,
            offer.offerAsset,
            offer.availableAmount,
            _feeAsset,
            _feeAmount,
            ReasonCancel,
            ReasonCancelFeeGive,
            ReasonCancelFeeReceive
        );

        emit Cancel(offer.maker, _offerHash);
    }

    /// @dev Performs an `ecrecover` operation for signed message hashes
    /// in accordance to EIP-191.
    function _recoverAddress(bytes32 _hash, uint8 _v, bytes32 _r, bytes32 _s)
        private
        pure
        returns (address)
    {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, _hash));
        return ecrecover(prefixedHash, _v, _r, _s);
    }

    /// @dev Decreases a user's balance while adding a cut from the decrement
    /// to be paid as fees to the operator. Reason codes should be provided
    /// to be emitted with events for tracking.
    function _decreaseBalanceAndPayFees(
        address _user,
        address _token,
        uint256 _amount,
        address _feeAsset,
        uint256 _feeAmount,
        uint8 _reason,
        uint8 _feeGiveReason,
        uint8 _feeReceiveReason
    )
        private
    {
        uint256 totalAmount = _amount;

        if (_feeAsset == _token) {
            totalAmount = _amount.add(_feeAmount);
        }

        balances[_user][_token] = balances[_user][_token].sub(totalAmount);
        emit BalanceDecrease(_user, _token, totalAmount, _reason);

        _payFees(_user, _token, _feeAsset, _feeAmount, _feeGiveReason, _feeReceiveReason);
    }

    /// @dev Increases a user's balance while deducting a cut from the increment
    /// to be paid as fees to the operator. Reason codes should be provided
    /// to be emitted with events for tracking.
    function _increaseBalanceAndPayFees(
        address _user,
        address _token,
        uint256 _amount,
        address _feeAsset,
        uint256 _feeAmount,
        uint8 _reason,
        uint8 _feeGiveReason,
        uint8 _feeReceiveReason
    )
        private
    {
        uint256 totalAmount = _amount;

        if (_feeAsset == _token) {
            totalAmount = _amount.sub(_feeAmount);
        }

        balances[_user][_token] = balances[_user][_token].add(totalAmount);
        emit BalanceIncrease(_user, _token, totalAmount, _reason);

        _payFees(_user, _token, _feeAsset, _feeAmount, _feeGiveReason, _feeReceiveReason);
    }

    /// @dev Pays fees to the operator, attaching the specified reason codes
    /// to the emitted event, only deducting from the `_user` balance if the
    /// `_token` does not match `_feeAsset`.
    /// IMPORTANT: In the event that the `_token` matches `_feeAsset`,
    /// there should a reduction in balance increment carried out separately,
    /// to ensure balance consistency.
    function _payFees(
        address _user,
        address _token,
        address _feeAsset,
        uint256 _feeAmount,
        uint8 _feeGiveReason,
        uint8 _feeReceiveReason
    )
        private
    {
        if (_feeAmount == 0) {
            return;
        }

        // if the feeAsset does not match the token then the feeAmount needs to be separately deducted
        if (_feeAsset != _token) {
            balances[_user][_feeAsset] = balances[_user][_feeAsset].sub(_feeAmount);
            emit BalanceDecrease(_user, _feeAsset, _feeAmount, _feeGiveReason);
        }

        balances[operator][_feeAsset] = balances[operator][_feeAsset].add(_feeAmount);
        emit BalanceIncrease(operator, _feeAsset, _feeAmount, _feeReceiveReason);
    }

    /// @dev Pays fees to the operator, attaching the specified reason codes to the emitted event.
    function _paySeparateFees(
        address _user,
        address _feeAsset,
        uint256 _feeAmount,
        uint8 _feeGiveReason,
        uint8 _feeReceiveReason
    )
        private
    {
        if (_feeAmount == 0) {
            return;
        }

        balances[_user][_feeAsset] = balances[_user][_feeAsset].sub(_feeAmount);
        emit BalanceDecrease(_user, _feeAsset, _feeAmount, _feeGiveReason);

        balances[operator][_feeAsset] = balances[operator][_feeAsset].add(_feeAmount);
        emit BalanceIncrease(operator, _feeAsset, _feeAmount, _feeReceiveReason);
    }

    /// @dev Ensures that the address is a valid user address.
    function _validateAddress(address _address)
        private
        pure
    {
        require(
            _address != address(0),
            'Invalid address'
        );
    }

    /// @dev Ensures a hash hasn't been already used, which would mean
    /// a repeated set of arguments and nonce was used. This prevents
    /// replay attacks.
    function _validateAndAddHash(bytes32 _hash)
        private
    {
        require(
            usedHashes[_hash] != true,
            "hash already used"
        );

        usedHashes[_hash] = true;
    }

    /// @dev Ensure that the address is a deployed contract
    function _validateIsContract(address addr) private view {
        assembly {
            if iszero(extcodesize(addr)) { revert(0, 0) }
        }
    }

    /// @dev Fix for ERC-20 tokens that do not have proper return type
    /// See: https://github.com/ethereum/solidity/issues/4116
    /// https://medium.com/loopring-protocol/an-incompatibility-in-smart-contract-threatening-dapp-ecosystem-72b8ca5db4da
    /// https://github.com/sec-bit/badERC20Fix/blob/master/badERC20Fix.sol
    function _getSanitizedReturnValue()
        private
        pure
        returns (bool)
    {
        uint256 result = 0;
        assembly {
            switch returndatasize
            case 0 {    // this is an non-standard ERC-20 token
                result := 1 // assume success on no revert
            }
            case 32 {   // this is a standard ERC-20 token
                returndatacopy(0, 0, 32)
                result := mload(0)
            }
            default {   // this is not an ERC-20 token
                revert(0, 0) // revert for safety
            }
        }
        return result != 0;
    }
}

// File: contracts/AtomicBroker.sol

pragma solidity 0.4.25;



/// @title The Atomic Swap contract for Switcheo Exchange
/// @author Switcheo Network
/// @notice This contract faciliates crosschain trades
/// between users through a time locked Atomic Swap.
/// The contract transfers assets by updating the balances
/// in the Switcheo Broker contract.
contract AtomicBroker {
    using SafeMath for uint256;

    // The Switcheo Broker contract
    Broker public broker;

    // Creating a swap
    uint8 constant ReasonSwapMakerGive = 0x30;
    uint8 constant ReasonSwapHolderReceive = 0x31;
    uint8 constant ReasonSwapMakerFeeGive = 0x32;
    uint8 constant ReasonSwapHolderFeeReceive = 0x33;

    // Executing a swap
    uint8 constant ReasonSwapHolderGive = 0x34;
    uint8 constant ReasonSwapTakerReceive = 0x35;
    uint8 constant ReasonSwapFeeGive = 0x36;
    uint8 constant ReasonSwapFeeReceive = 0x37;

    // Cancelling a swap
    uint8 constant ReasonSwapCancelMakerReceive = 0x38;
    uint8 constant ReasonSwapCancelHolderGive = 0x39;
    uint8 constant ReasonSwapCancelFeeGive = 0x3A;
    uint8 constant ReasonSwapCancelFeeReceive = 0x3B;
    uint8 constant ReasonSwapCancelFeeRefundGive = 0x3C;
    uint8 constant ReasonSwapCancelFeeRefundReceive = 0x3D;

    // Swaps by: swapHash => swapIsActive
    mapping(bytes32 => bool) public swaps;
    // A record of which hashes have been used before
    mapping(bytes32 => bool) public usedHashes;

    // Emitted when a new swap is created
    event CreateSwap(
        address indexed maker,
        address indexed taker,
        address token,
        uint256 amount,
        bytes32 indexed hashedSecret,
        uint256 expiryTime,
        address feeAsset,
        uint256 feeAmount
    );

    // Emitted when a swap is executed
    event ExecuteSwap(bytes32 indexed hashedSecret);

    // Emitted when a swap is cancelled
    event CancelSwap(bytes32 indexed hashedSecret);

    /// @notice Initializes the Atomic Broker contract
    /// @dev The broker is initialized to the Switcheo Broker
    constructor(address brokerAddress)
        public
    {
        broker = Broker(brokerAddress);
    }

    modifier onlyCoordinator() {
        require(
            msg.sender == address(broker.coordinator()),
            "Invalid sender"
        );
        _;
    }

    /// @notice Approves the Broker contract to update balances for this contract
    /// @dev The swap maker's balances are locked by transferring the balance to be
    /// locked to this contract within the Broker contract.
    /// To release the locked balances to the swap taker, this contract must approve
    /// itself as a spender of its own balances within the Broker contract.
    function approveBroker()
        external
    {
        broker.approveSpender(address(this));
    }

    /// @notice Creates a swap to initiate the transfer of assets.
    /// @dev Creates a swap to transfer `_amount` of `_token` to `_taker`
    /// The transfer is completed when executeSwap is called with the correct
    /// preimage matching the `_hashedSecret`.
    /// If executeSwap is not called, the transfer can be cancelled after
    /// `expiryTime` has passed.
    /// This operation can only be invoked by the coordinator.
    /// @param _maker The address of the user making the swap
    /// @param _taker The address of the user taking the swap
    /// @param _token The address of the token to be transferred
    /// @param _amount The number of tokens to be transferred
    /// @param _hashedSecret The hash of the secret decided on by the maker
    /// @param _expiryTime The epoch time of when the swap becomes cancellable
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _v The `v` component of the `_maker`'s signature
    /// @param _r The `r` component of the `_maker`'s signature
    /// @param _s The `s` component of the `_maker`'s signature
    function createSwap(
        address _maker,
        address _taker,
        address _token,
        uint256 _amount,
        bytes32 _hashedSecret,
        uint256 _expiryTime,
        address _feeAsset,
        uint256 _feeAmount,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    )
        external
        onlyCoordinator
    {
        require(
            _amount > 0,
            "Invalid amount"
        );

        require(
            _expiryTime > now,
            "Invalid expiry time"
        );

        _validateAndAddHash(_hashedSecret);

        bytes32 msgHash = _hashSwapParams(
            _maker,
            _taker,
            _token,
            _amount,
            _hashedSecret,
            _expiryTime,
            _feeAsset,
            _feeAmount
        );

        require(
            _recoverAddress(msgHash, _v, _r, _s) == _maker,
            "Invalid signature"
        );

        // This is needed because the _feeAmount is deducted from the locked _amount
        // when the swap is executed
        if (_feeAsset == _token) {
            require(
                _feeAmount < _amount,
                "Fee amount exceeds amount"
            );
        }

        // Lock swap amount into this contract
        broker.spendFrom(
            _maker,
            address(this),
            _amount,
            _token,
            ReasonSwapMakerGive,
            ReasonSwapHolderReceive
        );

        // Lock fee amount into this contract
        if (_feeAsset != _token)
        {
            broker.spendFrom(
                _maker,
                address(this),
                _feeAmount,
                _feeAsset,
                ReasonSwapMakerFeeGive,
                ReasonSwapHolderFeeReceive
            );
        }

        // Mark swap as active
        swaps[msgHash] = true;

        emit CreateSwap(
            _maker,
            _taker,
            _token,
            _amount,
            _hashedSecret,
            _expiryTime,
            _feeAsset,
            _feeAmount
        );
    }

    /// @notice Executes a swap that had been previously made using `createSwap`.
    /// @dev Transfers the previously locked asset from createSwap to the swap taker.
    /// The original swap parameters need to be resent as only the hash of these
    /// parameters are stored in `swaps`.
    /// @param _maker The address of the user making the swap
    /// @param _taker The address of the user taking the swap
    /// @param _token The address of the token to be transferred
    /// @param _amount The number of tokens to be transferred
    /// @param _hashedSecret The hash of the secret decided on by the maker
    /// @param _expiryTime The epoch time of when the swap becomes cancellable
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _preimage The preimage matching the _hashedSecret
    function executeSwap (
        address _maker,
        address _taker,
        address _token,
        uint256 _amount,
        bytes32 _hashedSecret,
        uint256 _expiryTime,
        address _feeAsset,
        uint256 _feeAmount,
        bytes _preimage
    )
        external
    {
        bytes32 msgHash = _hashSwapParams(
            _maker,
            _taker,
            _token,
            _amount,
            _hashedSecret,
            _expiryTime,
            _feeAsset,
            _feeAmount
        );

        require(
            swaps[msgHash] == true,
            "Swap is inactive"
        );

        require(
            sha256(abi.encodePacked(sha256(_preimage))) == _hashedSecret,
            "Invalid preimage"
        );

        uint256 takeAmount = _amount;

        if (_token == _feeAsset) {
            takeAmount -= _feeAmount;
        }

        // Mark swap as inactive
        delete swaps[msgHash];

        // Transfer take amount to taker
        broker.spendFrom(
            address(this),
            _taker,
            takeAmount,
            _token,
            ReasonSwapHolderGive,
            ReasonSwapTakerReceive
        );

        // Transfer fee amount to operator
        if (_feeAmount > 0) {
            broker.spendFrom(
                address(this),
                address(broker.operator()),
                _feeAmount,
                _feeAsset,
                ReasonSwapFeeGive,
                ReasonSwapFeeReceive
            );
        }

        emit ExecuteSwap(_hashedSecret);
    }


    /// @notice Cancels a swap that had been previously made using `createSwap`.
    /// @dev Cancels the swap with matching msgHash, releasing the locked assets
    /// back to the maker.
    /// The original swap parameters need to be resent as only the hash of these
    /// parameters are stored in `swaps`.
    /// The `_cancelFeeAmount` is deducted from the `_feeAmount` of the original swap.
    /// The remaining fee amount is refunded to the user.
    /// If the sender is not the coordinator, then the full `_feeAmount` is deducted.
    /// This gives the coordinator control to incentivise users to complete a swap once initiated.
    /// @param _maker The address of the user making the swap
    /// @param _taker The address of the user taking the swap
    /// @param _token The address of the token to be transferred
    /// @param _amount The number of tokens to be transferred
    /// @param _hashedSecret The hash of the secret decided on by the maker
    /// @param _expiryTime The epoch time of when the swap becomes cancellable
    /// @param _feeAsset The address of the token to use for fee payment
    /// @param _feeAmount The amount of tokens to pay as fees to the operator
    /// @param _cancelFeeAmount The number of tokens from the original `_feeAmount` to be deducted as
    /// cancellation fees
    function cancelSwap (
        address _maker,
        address _taker,
        address _token,
        uint256 _amount,
        bytes32 _hashedSecret,
        uint256 _expiryTime,
        address _feeAsset,
        uint256 _feeAmount,
        uint256 _cancelFeeAmount
    )
        external
    {
        require(
            _expiryTime <= now,
            "Cancellation time not yet reached"
        );

        bytes32 msgHash = _hashSwapParams(
            _maker,
            _taker,
            _token,
            _amount,
            _hashedSecret,
            _expiryTime,
            _feeAsset,
            _feeAmount
        );

        require(
            swaps[msgHash] == true,
            "Swap is inactive"
        );

        uint256 cancelFeeAmount = _cancelFeeAmount;

        // Charge the maximum cancelFeeAmount if not invoked by the coordinator
        if (msg.sender != address(broker.coordinator())) {
            cancelFeeAmount = _feeAmount;
        }

        require(
            cancelFeeAmount <= _feeAmount,
            "Cancel fee must be less than swap fee"
        );

        uint256 refundAmount = _amount;

        if (_token == _feeAsset) {
            refundAmount -= cancelFeeAmount;
        }

        // Mark the swap as inactive
        delete swaps[msgHash];

        // Refund the swap maker
        broker.spendFrom(
            address(this),
            _maker,
            refundAmount,
            _token,
            ReasonSwapCancelHolderGive,
            ReasonSwapCancelMakerReceive
        );

        // Transfer cancel fee to operator
        if (cancelFeeAmount > 0) {
            broker.spendFrom(
                address(this),
                address(broker.operator()),
                cancelFeeAmount,
                _feeAsset,
                ReasonSwapCancelFeeGive,
                ReasonSwapCancelFeeReceive
            );
        }

        // If the fee asset is different from the swap asset
        // then the remaining fee must be separately refunded to the maker
        uint256 refundFeeAmount = _feeAmount - cancelFeeAmount;
        if (_token != _feeAsset && refundFeeAmount > 0) {
            broker.spendFrom(
                address(this),
                _maker,
                refundFeeAmount,
                _feeAsset,
                ReasonSwapCancelFeeRefundGive,
                ReasonSwapCancelFeeRefundReceive
            );
        }

        emit CancelSwap(_hashedSecret);
    }

    function _hashSwapParams(
        address _maker,
        address _taker,
        address _token,
        uint256 _amount,
        bytes32 _hashedSecret,
        uint256 _expiryTime,
        address _feeAsset,
        uint256 _feeAmount
    )
        private
        pure
        returns (bytes32)
    {
        return keccak256(abi.encodePacked(
            "swap",
            _maker,
            _taker,
            _token,
            _amount,
            _hashedSecret,
            _expiryTime,
            _feeAsset,
            _feeAmount
        ));
    }

    /// @dev Performs an `ecrecover` operation for signed message hashes
    /// in accordance to EIP-191.
    function _recoverAddress(bytes32 _hash, uint8 _v, bytes32 _r, bytes32 _s)
        private
        pure
        returns (address)
    {
        bytes memory prefix = "\x19Ethereum Signed Message:\n32";
        bytes32 prefixedHash = keccak256(abi.encodePacked(prefix, _hash));
        return ecrecover(prefixedHash, _v, _r, _s);
    }

    /// @dev Ensures a hash hasn't been already used.
    /// This prevents replay attacks.
    function _validateAndAddHash(bytes32 _hash)
        private
    {
        require(
            usedHashes[_hash] != true,
            "hash already used"
        );

        usedHashes[_hash] = true;
    }
}

Contract Security Audit

Contract ABI

[{"constant":false,"inputs":[{"name":"_maker","type":"address"},{"name":"_taker","type":"address"},{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_hashedSecret","type":"bytes32"},{"name":"_expiryTime","type":"uint256"},{"name":"_feeAsset","type":"address"},{"name":"_feeAmount","type":"uint256"},{"name":"_preimage","type":"bytes"}],"name":"executeSwap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maker","type":"address"},{"name":"_taker","type":"address"},{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_hashedSecret","type":"bytes32"},{"name":"_expiryTime","type":"uint256"},{"name":"_feeAsset","type":"address"},{"name":"_feeAmount","type":"uint256"},{"name":"_cancelFeeAmount","type":"uint256"}],"name":"cancelSwap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_maker","type":"address"},{"name":"_taker","type":"address"},{"name":"_token","type":"address"},{"name":"_amount","type":"uint256"},{"name":"_hashedSecret","type":"bytes32"},{"name":"_expiryTime","type":"uint256"},{"name":"_feeAsset","type":"address"},{"name":"_feeAmount","type":"uint256"},{"name":"_v","type":"uint8"},{"name":"_r","type":"bytes32"},{"name":"_s","type":"bytes32"}],"name":"createSwap","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"approveBroker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"broker","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"usedHashes","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"swaps","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"brokerAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"maker","type":"address"},{"indexed":true,"name":"taker","type":"address"},{"indexed":false,"name":"token","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":true,"name":"hashedSecret","type":"bytes32"},{"indexed":false,"name":"expiryTime","type":"uint256"},{"indexed":false,"name":"feeAsset","type":"address"},{"indexed":false,"name":"feeAmount","type":"uint256"}],"name":"CreateSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"hashedSecret","type":"bytes32"}],"name":"ExecuteSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"hashedSecret","type":"bytes32"}],"name":"CancelSwap","type":"event"}]

608060405234801561001057600080fd5b506040516020806114e1833981016040525160008054600160a060020a03909216600160a060020a031990921691909117905561148f806100526000396000f3006080604052600436106100695763ffffffff60e060020a6000350416630977873b811461006e57806327eabac3146100c0578063571e76f71461010657806390a6ba8814610157578063abff01101461016c578063aef18bf71461019d578063eb84e7f2146101c9575b600080fd5b34801561007a57600080fd5b506100be600160a060020a036004803582169160248035821692604435831692606435926084359260a4359260c435169160e43591610104359182019101356101e1565b005b3480156100cc57600080fd5b506100be600160a060020a03600435811690602435811690604435811690606435906084359060a4359060c4351660e435610104356105dd565b34801561011257600080fd5b506100be600160a060020a03600435811690602435811690604435811690606435906084359060a4359060c4351660e43560ff61010435166101243561014435610b8d565b34801561016357600080fd5b506100be6110c6565b34801561017857600080fd5b50610181611140565b60408051600160a060020a039092168252519081900360200190f35b3480156101a957600080fd5b506101b560043561114f565b604080519115158252519081900360200190f35b3480156101d557600080fd5b506101b5600435611164565b6000806101f48c8c8c8c8c8c8c8c611179565b60008181526001602081905260409091205491935060ff909116151514610265576040805160e560020a62461bcd02815260206004820152601060248201527f5377617020697320696e61637469766500000000000000000000000000000000604482015290519081900360640190fd5b87600019166002808686604051808383808284378201915050925050506020604051808303816000865af11580156102a1573d6000803e3d6000fd5b5050506040513d60208110156102b657600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b602083106103025780518252601f1990920191602091820191016102e3565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015610343573d6000803e3d6000fd5b5050506040513d602081101561035857600080fd5b5051146103af576040805160e560020a62461bcd02815260206004820152601060248201527f496e76616c696420707265696d61676500000000000000000000000000000000604482015290519081900360640190fd5b88905085600160a060020a03168a600160a060020a031614156103d0578490035b600082815260016020526040808220805460ff19169055815481517f66acab4c000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a038f81166024830152604482018690528e8116606483015260346084830152603560a4830152925192909116926366acab4c9260c48084019382900301818387803b15801561046957600080fd5b505af115801561047d573d6000803e3d6000fd5b5050505060008511156105a45760008054604080517f570ca7350000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926366acab4c923092859263570ca735926004808401936020939083900390910190829087803b1580156104f557600080fd5b505af1158015610509573d6000803e3d6000fd5b505050506040513d602081101561051f57600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a0393841660048201529183166024830152604482018a9052918a16606482015260366084820152603760a4820152905160c480830192600092919082900301818387803b15801561058b57600080fd5b505af115801561059f573d6000803e3d6000fd5b505050505b60405188907fb8f777c2682f5c8db9eca27195e9f2a08abba31865831209927a9e282ca1007e90600090a2505050505050505050505050565b600080808042881115610660576040805160e560020a62461bcd02815260206004820152602160248201527f43616e63656c6c6174696f6e2074696d65206e6f74207965742072656163686560448201527f6400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6106708d8d8d8d8d8d8d8d611179565b60008181526001602081905260409091205491955060ff9091161515146106e1576040805160e560020a62461bcd02815260206004820152601060248201527f5377617020697320696e61637469766500000000000000000000000000000000604482015290519081900360640190fd5b8492506000809054906101000a9004600160a060020a0316600160a060020a0316630a0090976040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561073657600080fd5b505af115801561074a573d6000803e3d6000fd5b505050506040513d602081101561076057600080fd5b5051600160a060020a03163314610775578592505b858311156107f3576040805160e560020a62461bcd02815260206004820152602560248201527f43616e63656c20666565206d757374206265206c657373207468616e2073776160448201527f7020666565000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b89915086600160a060020a03168b600160a060020a031614156108165782820391505b60016000856000191660001916815260200190815260200160002060006101000a81549060ff02191690556000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c308f858f603960386040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b15801561090a57600080fd5b505af115801561091e573d6000803e3d6000fd5b505050506000831115610a455760008054604080517f570ca7350000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926366acab4c923092859263570ca735926004808401936020939083900390910190829087803b15801561099657600080fd5b505af11580156109aa573d6000803e3d6000fd5b505050506040513d60208110156109c057600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a039384166004820152918316602483015260448201889052918b166064820152603a6084820152603b60a4820152905160c480830192600092919082900301818387803b158015610a2c57600080fd5b505af1158015610a40573d6000803e3d6000fd5b505050505b828603905086600160a060020a03168b600160a060020a031614158015610a6c5750600081115b15610b53576000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c308f848b603c603d6040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b158015610b3a57600080fd5b505af1158015610b4e573d6000803e3d6000fd5b505050505b60405189907fad8f5783ccaf65c71de9f05c4204da5e5586193083754a5955a1604dc1aedc3790600090a250505050505050505050505050565b60008060009054906101000a9004600160a060020a0316600160a060020a0316630a0090976040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610be157600080fd5b505af1158015610bf5573d6000803e3d6000fd5b505050506040513d6020811015610c0b57600080fd5b5051600160a060020a03163314610c6c576040805160e560020a62461bcd02815260206004820152600e60248201527f496e76616c69642073656e646572000000000000000000000000000000000000604482015290519081900360640190fd5b60008911610cc4576040805160e560020a62461bcd02815260206004820152600e60248201527f496e76616c696420616d6f756e74000000000000000000000000000000000000604482015290519081900360640190fd5b428711610d1b576040805160e560020a62461bcd02815260206004820152601360248201527f496e76616c6964206578706972792074696d6500000000000000000000000000604482015290519081900360640190fd5b610d248861127b565b610d348c8c8c8c8c8c8c8c611179565b90508b600160a060020a0316610d4c82868686611302565b600160a060020a031614610daa576040805160e560020a62461bcd02815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015290519081900360640190fd5b89600160a060020a031686600160a060020a03161415610e1b57888510610e1b576040805160e560020a62461bcd02815260206004820152601960248201527f46656520616d6f756e74206578636565647320616d6f756e7400000000000000604482015290519081900360640190fd5b6000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c8d308c8e603060316040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b158015610ee457600080fd5b505af1158015610ef8573d6000803e3d6000fd5b50505050600160a060020a03868116908b1614610ff1576000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c8d30888a603260336040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b158015610fd857600080fd5b505af1158015610fec573d6000803e3d6000fd5b505050505b6001806000836000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555087600019168b600160a060020a03168d600160a060020a03167f8fdd4312601e56c11831f8c000540bf66966b7c19933ec42f44d81e56cd3df368d8d8c8c8c6040518086600160a060020a0316600160a060020a0316815260200185815260200184815260200183600160a060020a0316600160a060020a031681526020018281526020019550505050505060405180910390a4505050505050505050505050565b60008054604080517f099a0aae0000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a039092169263099a0aae9260248084019382900301818387803b15801561112657600080fd5b505af115801561113a573d6000803e3d6000fd5b50505050565b600054600160a060020a031681565b60026020526000908152604090205460ff1681565b60016020526000908152604090205460ff1681565b604080517f73776170000000000000000000000000000000000000000000000000000000006020808301919091526c01000000000000000000000000600160a060020a03808d1682026024850152808c1682026038850152808b168202604c850152606084018a90526080840189905260a0840188905286160260c083015260d48083018590528351808403909101815260f4909201928390528151600093918291908401908083835b602083106112425780518252601f199092019160209182019101611223565b5181516020939093036101000a600019018019909116921691909117905260405192018290039091209c9b505050505050505050505050565b60008181526002602052604090205460ff161515600114156112e7576040805160e560020a62461bcd02815260206004820152601160248201527f6861736820616c72656164792075736564000000000000000000000000000000604482015290519081900360640190fd5b6000908152600260205260409020805460ff19166001179055565b604080518082018252601c8082527f19457468657265756d205369676e6564204d6573736167653a0a33320000000060208084019182529351600094859385938b939092019182918083835b6020831061136d5780518252601f19909201916020918201910161134e565b51815160209384036101000a600019018019909216911617905292019384525060408051808503815293820190819052835193945092839250908401908083835b602083106113cd5780518252601f1990920191602091820191016113ae565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080845283830180875282905260ff8e1684870152606084018d9052608084018c905294519097506001965060a080840196509194601f19820194509281900390910191865af115801561144d573d6000803e3d6000fd5b5050604051601f190151989750505050505050505600a165627a7a72305820e9b64cdcb95efc18cbd3f73ca584dcb3d3c56644dbb4bab9de27d9940eaf6ede0029000000000000000000000000ba3ed686cc32ffa8664628b1e96d8022e40543de

Deployed Bytecode

0x6080604052600436106100695763ffffffff60e060020a6000350416630977873b811461006e57806327eabac3146100c0578063571e76f71461010657806390a6ba8814610157578063abff01101461016c578063aef18bf71461019d578063eb84e7f2146101c9575b600080fd5b34801561007a57600080fd5b506100be600160a060020a036004803582169160248035821692604435831692606435926084359260a4359260c435169160e43591610104359182019101356101e1565b005b3480156100cc57600080fd5b506100be600160a060020a03600435811690602435811690604435811690606435906084359060a4359060c4351660e435610104356105dd565b34801561011257600080fd5b506100be600160a060020a03600435811690602435811690604435811690606435906084359060a4359060c4351660e43560ff61010435166101243561014435610b8d565b34801561016357600080fd5b506100be6110c6565b34801561017857600080fd5b50610181611140565b60408051600160a060020a039092168252519081900360200190f35b3480156101a957600080fd5b506101b560043561114f565b604080519115158252519081900360200190f35b3480156101d557600080fd5b506101b5600435611164565b6000806101f48c8c8c8c8c8c8c8c611179565b60008181526001602081905260409091205491935060ff909116151514610265576040805160e560020a62461bcd02815260206004820152601060248201527f5377617020697320696e61637469766500000000000000000000000000000000604482015290519081900360640190fd5b87600019166002808686604051808383808284378201915050925050506020604051808303816000865af11580156102a1573d6000803e3d6000fd5b5050506040513d60208110156102b657600080fd5b50516040805160208181019390935281518082038401815290820191829052805190928291908401908083835b602083106103025780518252601f1990920191602091820191016102e3565b51815160209384036101000a600019018019909216911617905260405191909301945091925050808303816000865af1158015610343573d6000803e3d6000fd5b5050506040513d602081101561035857600080fd5b5051146103af576040805160e560020a62461bcd02815260206004820152601060248201527f496e76616c696420707265696d61676500000000000000000000000000000000604482015290519081900360640190fd5b88905085600160a060020a03168a600160a060020a031614156103d0578490035b600082815260016020526040808220805460ff19169055815481517f66acab4c000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a038f81166024830152604482018690528e8116606483015260346084830152603560a4830152925192909116926366acab4c9260c48084019382900301818387803b15801561046957600080fd5b505af115801561047d573d6000803e3d6000fd5b5050505060008511156105a45760008054604080517f570ca7350000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926366acab4c923092859263570ca735926004808401936020939083900390910190829087803b1580156104f557600080fd5b505af1158015610509573d6000803e3d6000fd5b505050506040513d602081101561051f57600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a0393841660048201529183166024830152604482018a9052918a16606482015260366084820152603760a4820152905160c480830192600092919082900301818387803b15801561058b57600080fd5b505af115801561059f573d6000803e3d6000fd5b505050505b60405188907fb8f777c2682f5c8db9eca27195e9f2a08abba31865831209927a9e282ca1007e90600090a2505050505050505050505050565b600080808042881115610660576040805160e560020a62461bcd02815260206004820152602160248201527f43616e63656c6c6174696f6e2074696d65206e6f74207965742072656163686560448201527f6400000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b6106708d8d8d8d8d8d8d8d611179565b60008181526001602081905260409091205491955060ff9091161515146106e1576040805160e560020a62461bcd02815260206004820152601060248201527f5377617020697320696e61637469766500000000000000000000000000000000604482015290519081900360640190fd5b8492506000809054906101000a9004600160a060020a0316600160a060020a0316630a0090976040518163ffffffff1660e060020a028152600401602060405180830381600087803b15801561073657600080fd5b505af115801561074a573d6000803e3d6000fd5b505050506040513d602081101561076057600080fd5b5051600160a060020a03163314610775578592505b858311156107f3576040805160e560020a62461bcd02815260206004820152602560248201527f43616e63656c20666565206d757374206265206c657373207468616e2073776160448201527f7020666565000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b89915086600160a060020a03168b600160a060020a031614156108165782820391505b60016000856000191660001916815260200190815260200160002060006101000a81549060ff02191690556000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c308f858f603960386040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b15801561090a57600080fd5b505af115801561091e573d6000803e3d6000fd5b505050506000831115610a455760008054604080517f570ca7350000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216926366acab4c923092859263570ca735926004808401936020939083900390910190829087803b15801561099657600080fd5b505af11580156109aa573d6000803e3d6000fd5b505050506040513d60208110156109c057600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a039384166004820152918316602483015260448201889052918b166064820152603a6084820152603b60a4820152905160c480830192600092919082900301818387803b158015610a2c57600080fd5b505af1158015610a40573d6000803e3d6000fd5b505050505b828603905086600160a060020a03168b600160a060020a031614158015610a6c5750600081115b15610b53576000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c308f848b603c603d6040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b158015610b3a57600080fd5b505af1158015610b4e573d6000803e3d6000fd5b505050505b60405189907fad8f5783ccaf65c71de9f05c4204da5e5586193083754a5955a1604dc1aedc3790600090a250505050505050505050505050565b60008060009054906101000a9004600160a060020a0316600160a060020a0316630a0090976040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015610be157600080fd5b505af1158015610bf5573d6000803e3d6000fd5b505050506040513d6020811015610c0b57600080fd5b5051600160a060020a03163314610c6c576040805160e560020a62461bcd02815260206004820152600e60248201527f496e76616c69642073656e646572000000000000000000000000000000000000604482015290519081900360640190fd5b60008911610cc4576040805160e560020a62461bcd02815260206004820152600e60248201527f496e76616c696420616d6f756e74000000000000000000000000000000000000604482015290519081900360640190fd5b428711610d1b576040805160e560020a62461bcd02815260206004820152601360248201527f496e76616c6964206578706972792074696d6500000000000000000000000000604482015290519081900360640190fd5b610d248861127b565b610d348c8c8c8c8c8c8c8c611179565b90508b600160a060020a0316610d4c82868686611302565b600160a060020a031614610daa576040805160e560020a62461bcd02815260206004820152601160248201527f496e76616c6964207369676e6174757265000000000000000000000000000000604482015290519081900360640190fd5b89600160a060020a031686600160a060020a03161415610e1b57888510610e1b576040805160e560020a62461bcd02815260206004820152601960248201527f46656520616d6f756e74206578636565647320616d6f756e7400000000000000604482015290519081900360640190fd5b6000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c8d308c8e603060316040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b158015610ee457600080fd5b505af1158015610ef8573d6000803e3d6000fd5b50505050600160a060020a03868116908b1614610ff1576000809054906101000a9004600160a060020a0316600160a060020a03166366acab4c8d30888a603260336040518763ffffffff1660e060020a0281526004018087600160a060020a0316600160a060020a0316815260200186600160a060020a0316600160a060020a0316815260200185815260200184600160a060020a0316600160a060020a031681526020018360ff1660ff1681526020018260ff1660ff1681526020019650505050505050600060405180830381600087803b158015610fd857600080fd5b505af1158015610fec573d6000803e3d6000fd5b505050505b6001806000836000191660001916815260200190815260200160002060006101000a81548160ff02191690831515021790555087600019168b600160a060020a03168d600160a060020a03167f8fdd4312601e56c11831f8c000540bf66966b7c19933ec42f44d81e56cd3df368d8d8c8c8c6040518086600160a060020a0316600160a060020a0316815260200185815260200184815260200183600160a060020a0316600160a060020a031681526020018281526020019550505050505060405180910390a4505050505050505050505050565b60008054604080517f099a0aae0000000000000000000000000000000000000000000000000000000081523060048201529051600160a060020a039092169263099a0aae9260248084019382900301818387803b15801561112657600080fd5b505af115801561113a573d6000803e3d6000fd5b50505050565b600054600160a060020a031681565b60026020526000908152604090205460ff1681565b60016020526000908152604090205460ff1681565b604080517f73776170000000000000000000000000000000000000000000000000000000006020808301919091526c01000000000000000000000000600160a060020a03808d1682026024850152808c1682026038850152808b168202604c850152606084018a90526080840189905260a0840188905286160260c083015260d48083018590528351808403909101815260f4909201928390528151600093918291908401908083835b602083106112425780518252601f199092019160209182019101611223565b5181516020939093036101000a600019018019909116921691909117905260405192018290039091209c9b505050505050505050505050565b60008181526002602052604090205460ff161515600114156112e7576040805160e560020a62461bcd02815260206004820152601160248201527f6861736820616c72656164792075736564000000000000000000000000000000604482015290519081900360640190fd5b6000908152600260205260409020805460ff19166001179055565b604080518082018252601c8082527f19457468657265756d205369676e6564204d6573736167653a0a33320000000060208084019182529351600094859385938b939092019182918083835b6020831061136d5780518252601f19909201916020918201910161134e565b51815160209384036101000a600019018019909216911617905292019384525060408051808503815293820190819052835193945092839250908401908083835b602083106113cd5780518252601f1990920191602091820191016113ae565b51815160209384036101000a600019018019909216911617905260408051929094018290038220600080845283830180875282905260ff8e1684870152606084018d9052608084018c905294519097506001965060a080840196509194601f19820194509281900390910191865af115801561144d573d6000803e3d6000fd5b5050604051601f190151989750505050505050505600a165627a7a72305820e9b64cdcb95efc18cbd3f73ca584dcb3d3c56644dbb4bab9de27d9940eaf6ede0029

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

000000000000000000000000ba3ed686cc32ffa8664628b1e96d8022e40543de

-----Decoded View---------------
Arg [0] : brokerAddress (address): 0xba3Ed686cC32FfA8664628b1E96D8022e40543dE

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000ba3ed686cc32ffa8664628b1e96d8022e40543de


Swarm Source

bzzr://e9b64cdcb95efc18cbd3f73ca584dcb3d3c56644dbb4bab9de27d9940eaf6ede

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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