Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 18,320 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Execute Swap | 8711389 | 1836 days ago | IN | 0 ETH | 0.00033311 | ||||
Execute Swap | 8711389 | 1836 days ago | IN | 0 ETH | 0.00049811 | ||||
Create Swap | 8711385 | 1836 days ago | IN | 0 ETH | 0.00117042 | ||||
Create Swap | 8711385 | 1836 days ago | IN | 0 ETH | 0.00133542 | ||||
Execute Swap | 8711381 | 1836 days ago | IN | 0 ETH | 0.00036127 | ||||
Create Swap | 8711378 | 1836 days ago | IN | 0 ETH | 0.00136358 | ||||
Execute Swap | 8710768 | 1836 days ago | IN | 0 ETH | 0.00029558 | ||||
Create Swap | 8710765 | 1836 days ago | IN | 0 ETH | 0.0011145 | ||||
Execute Swap | 8710757 | 1836 days ago | IN | 0 ETH | 0.00029558 | ||||
Create Swap | 8710755 | 1836 days ago | IN | 0 ETH | 0.00111565 | ||||
Execute Swap | 8710476 | 1836 days ago | IN | 0 ETH | 0.00027254 | ||||
Execute Swap | 8710474 | 1836 days ago | IN | 0 ETH | 0.00040812 | ||||
Create Swap | 8710470 | 1836 days ago | IN | 0 ETH | 0.00095761 | ||||
Create Swap | 8710468 | 1836 days ago | IN | 0 ETH | 0.00109319 | ||||
Execute Swap | 8709583 | 1837 days ago | IN | 0 ETH | 0.00060866 | ||||
Create Swap | 8709575 | 1837 days ago | IN | 0 ETH | 0.00158405 | ||||
Execute Swap | 8709282 | 1837 days ago | IN | 0 ETH | 0.00027254 | ||||
Create Swap | 8709279 | 1837 days ago | IN | 0 ETH | 0.00109261 | ||||
Execute Swap | 8709264 | 1837 days ago | IN | 0 ETH | 0.00060808 | ||||
Create Swap | 8709258 | 1837 days ago | IN | 0 ETH | 0.00109607 | ||||
Execute Swap | 8709228 | 1837 days ago | IN | 0 ETH | 0.00047308 | ||||
Create Swap | 8709223 | 1837 days ago | IN | 0 ETH | 0.00109549 | ||||
Execute Swap | 8709223 | 1837 days ago | IN | 0 ETH | 0.00027312 | ||||
Execute Swap | 8709223 | 1837 days ago | IN | 0 ETH | 0.00040754 | ||||
Create Swap | 8709219 | 1837 days ago | IN | 0 ETH | 0.00095819 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
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
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 29 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.