Address Contract Verified
Address
0x0e87bF5286C4091e0eeb7814D802115dFBb4c4cd
Balance
31.8803 ETH
Nonce
1
Code Size
7938 bytes
Creator
0x7AB685a6...2271 at tx 0xdbfa3d8b...bebc84
Indexed Transactions
2 (24,417,337 → 24,417,347)
Value (indexed)
↓ 0.088747 ETH
Gas Used (indexed)
109,792
Contract Bytecode
7938 bytes
0x6080604052600436106101095760003560e01c80638eb4e0ad11610095578063de5785d511610064578063de5785d514610985578063e5994905146109ac578063e9600f12146109f5578063f1e03d6714610a53578063f5537ede14610ad157610109565b80638eb4e0ad14610345578063ad3b1b47146108d6578063b0eefabe1461090f578063da3e33971461094257610109565b806357938b2a116100dc57806357938b2a146102895780636548e9bc146102b75780636cc6cde1146102ea5780638406c0791461031b5780638da5cb5b1461033057610109565b806313af40351461010e57806324943c7d146101435780632cc9636c146101bf5780632d83549c14610231575b600080fd5b34801561011a57600080fd5b506101416004803603602081101561013157600080fd5b50356001600160a01b0316610b14565b005b34801561014f57600080fd5b50610141600480360361012081101561016757600080fd5b506001600160801b0319813516906001600160a01b03602082013581169160408101359091169060608101359061ffff6080820135169060ff60a082013581169160c08101359160e082013591610100013516610b85565b3480156101cb57600080fd5b5061021d600480360360a08110156101e257600080fd5b5080356001600160801b0319169060208101356001600160a01b03908116916040810135909116906060810135906080013561ffff16610f3a565b604080519115158252519081900360200190f35b34801561023d57600080fd5b5061025b6004803603602081101561025457600080fd5b5035610fa2565b60408051931515845263ffffffff90921660208401526001600160801b031682820152519081900360600190f35b34801561029557600080fd5b5061029e610fd5565b6040805163ffffffff9092168252519081900360200190f35b3480156102c357600080fd5b50610141600480360360208110156102da57600080fd5b50356001600160a01b0316610fe8565b3480156102f657600080fd5b506102ff611059565b604080516001600160a01b039092168252519081900360200190f35b34801561032757600080fd5b506102ff611068565b34801561033c57600080fd5b506102ff611077565b34801561035157600080fd5b50610886600480360361014081101561036957600080fd5b810190602081018135600160201b81111561038357600080fd5b82018360208201111561039557600080fd5b803590602001918460208302840111600160201b831117156103b657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561040557600080fd5b82018360208201111561041757600080fd5b803590602001918460208302840111600160201b8311171561043857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561048757600080fd5b82018360208201111561049957600080fd5b803590602001918460208302840111600160201b831117156104ba57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561050957600080fd5b82018360208201111561051b57600080fd5b803590602001918460208302840111600160201b8311171561053c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561058b57600080fd5b82018360208201111561059d57600080fd5b803590602001918460208302840111600160201b831117156105be57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561060d57600080fd5b82018360208201111561061f57600080fd5b803590602001918460208302840111600160201b8311171561064057600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561068f57600080fd5b8201836020820111156106a157600080fd5b803590602001918460208302840111600160201b831117156106c257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561071157600080fd5b82018360208201111561072357600080fd5b803590602001918460208302840111600160201b8311171561074457600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561079357600080fd5b8201836020820111156107a557600080fd5b803590602001918460208302840111600160201b831117156107c657600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561081557600080fd5b82018360208201111561082757600080fd5b803590602001918460208302840111600160201b8311171561084857600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611086945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156108c25781810151838201526020016108aa565b505050509050019250505060405180910390f35b3480156108e257600080fd5b50610141600480360360408110156108f957600080fd5b506001600160a01b03813516906020013561121b565b34801561091b57600080fd5b506101416004803603602081101561093257600080fd5b50356001600160a01b03166112ef565b34801561094e57600080fd5b506101416004803603606081101561096557600080fd5b506001600160a01b03813581169160208101359091169060400135611360565b34801561099157600080fd5b5061099a611440565b60408051918252519081900360200190f35b3480156109b857600080fd5b50610141600480360360808110156109cf57600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135611446565b348015610a0157600080fd5b5061021d600480360360a0811015610a1857600080fd5b5080356001600160801b0319169060208101356001600160a01b03908116916040810135909116906060810135906080013561ffff16611522565b6101416004803603610140811015610a6a57600080fd5b506001600160801b0319813516906001600160a01b03602082013581169160408101359091169060608101359061ffff6080820135169063ffffffff60a082013581169160c08101359091169060ff60e08201351690610100810135906101200135611581565b348015610add57600080fd5b5061014160048036036060811015610af457600080fd5b506001600160a01b03813581169160208101359091169060400135611874565b6001546001600160a01b03163314610b63576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610bd9576040805162461bcd60e51b815260206004820152601260248201527126bab9ba1031329030b93134ba3930ba37b960711b604482015290519081900360640190fd5b604080516001600160801b03198b16602080830191909152600360f81b60308301528251601181840301815260319092019092528051910120600090610c2190868686611923565b9050876001600160a01b0316816001600160a01b03161480610c545750886001600160a01b0316816001600160a01b0316145b610ca5576040805162461bcd60e51b815260206004820152601760248201527f4d757374206265206275796572206f722073656c6c6572000000000000000000604482015290519081900360640190fd5b610cad611e65565b6000610cbc8c8c8c8c8c611a39565b60408051606081018252925460ff81161515808552610100820463ffffffff166020860152600160281b9091046001600160801b0316918401919091529193509150610d47576040805162461bcd60e51b8152602060048201526015602482015274115cd8dc9bddc8191bd95cc81b9bdd08195e1a5cdd605a1b604482015290519081900360640190fd5b60648460ff161115610d8a5760405162461bcd60e51b8152600401808060200182810382526022815260200180611e866022913960400191505060405180910390fd5b60408201513a618d0402016001600160801b0316808a038a1015610de6576040805162461bcd60e51b815260206004820152600e60248201526d27bb32b9333637bb9032b93937b960911b604482015290519081900360640190fd5b600380548201905560008281526004602052604080822080546001600160a81b03191690555183917f65e0c7182ce84cd9087c1b07dc4b65875578877b885848e4be19ee312f2c3d3191a260ff851615610edc5761271061ffff8a168b0204606460ff87168c02048290038190038b811115610e9a576040805162461bcd60e51b815260206004820152600e60248201526d27bb32b9333637bb9032b93937b960911b604482015290519081900360640190fd5b60038054830190556040516001600160a01b038e169082156108fc029083906000818181858888f19350505050158015610ed8573d6000803e3d6000fd5b5050505b60648560ff161015610f2b576040516001600160a01b038d1690606487810360ff16848e03020480156108fc02916000818181858888f19350505050158015610f29573d6000803e3d6000fd5b505b50505050505050505050505050565b6000336001600160a01b03851614610f89576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba10313290313abcb2b960991b604482015290519081900360640190fd5b610f9886868686866000611abe565b9695505050505050565b60046020526000908152604090205460ff811690610100810463ffffffff1690600160281b90046001600160801b031683565b600254600160a01b900463ffffffff1681565b6001546001600160a01b03163314611037576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031681565b6002546001600160a01b031681565b6001546001600160a01b031681565b6060808b516040519080825280602002602001820160405280156110b4578160200160208202803883390190505b506002549091506000906001600160a01b031633146110d45760006110e2565b8c51616f54816110e057fe5b045b905060005b8d518160ff161015611209576111e28e8260ff168151811061110557fe5b60200260200101518e8360ff168151811061111c57fe5b60200260200101518e8460ff168151811061113357fe5b60200260200101518e8560ff168151811061114a57fe5b60200260200101518e8660ff168151811061116157fe5b60200260200101518e8760ff168151811061117857fe5b60200260200101518e8860ff168151811061118f57fe5b60200260200101518e8960ff16815181106111a657fe5b60200260200101518e8a60ff16815181106111bd57fe5b60200260200101518e8b60ff16815181106111d457fe5b60200260200101518c611bb6565b838260ff16815181106111f157fe5b911515602092830291909101909101526001016110e7565b50909c9b505050505050505050505050565b6001546001600160a01b0316331461126a576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b6003548111156112ab5760405162461bcd60e51b8152600401808060200182810382526026815260200180611ea86026913960400191505060405180910390fd5b6003805482900390556040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156112ea573d6000803e3d6000fd5b505050565b6001546001600160a01b0316331461133e576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031633146113af576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b826001600160a01b031663095ea7b383836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561140f57600080fd5b505af1158015611423573d6000803e3d6000fd5b505050506040513d602081101561143957600080fd5b5050505050565b60035481565b6001546001600160a01b03163314611495576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b604080516323b872dd60e01b81526001600160a01b0385811660048301528481166024830152604482018490529151918616916323b872dd916064808201926020929091908290030181600087803b1580156114f057600080fd5b505af1158015611504573d6000803e3d6000fd5b505050506040513d602081101561151a57600080fd5b505050505050565b6000336001600160a01b03861614611572576040805162461bcd60e51b815260206004820152600e60248201526d26bab9ba1031329039b2b63632b960911b604482015290519081900360640190fd5b610f9886868686866000611cab565b604080516001600160801b03198c166020808301919091526bffffffffffffffffffffffff1960608d811b821660308501528c901b166044830152605882018a90526001600160f01b031960f08a901b1660788301528251605a818403018152607a9092018352815191810191909120600081815260049092529190205460ff161561164b576040805162461bcd60e51b8152602060048201526014602482015273547261646520616c72656164792065786973747360601b604482015290519081900360640190fd5b6040805160208082018490526001600160e01b031960e08a811b82168486015289901b16604483015282516028818403018152604890920190925280519101206002546001600160a01b03166116a382878787611923565b6001600160a01b0316146116f0576040805162461bcd60e51b815260206004820152600f60248201526e26bab9ba103132903932b630bcb2b960891b604482015290519081900360640190fd5b8563ffffffff164210611742576040805162461bcd60e51b815260206004820152601560248201527414da59db985d1d5c99481a185cc8195e1c1a5c9959605a1b604482015290519081900360640190fd5b88341480156117515750600034115b611799576040805162461bcd60e51b8152602060048201526014602482015273125b98dbdc9c9958dd08195d1a195c881cd95b9d60621b604482015290519081900360640190fd5b600063ffffffff8816156117af578742016117b2565b60015b604080516060810182526001815263ffffffff808416602080840191825260008486018181528a8252600490925285812094518554935192516001600160801b0316600160281b0274ffffffffffffffffffffffffffffffff000000000019939095166101000264ffffffff001991151560ff199095169490941716929092171691909117909155905191925084917f102d25c49d33fcdb8976a3f2744e0785c98d9e43b88364859e6aec4ae82eff5c9190a250505050505050505050505050565b6001546001600160a01b031633146118c3576040805162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b604482015290519081900360640190fd5b826001600160a01b031663a9059cbb83836040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561140f57600080fd5b600060606040518060400160405280601c81526020017f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152509050600081876040516020018083805190602001908083835b602083106119955780518252601f199092019160209182019101611976565b51815160209384036101000a6000190180199092169116179052920193845250604080518085038152848301808352815191840191909120600090915281850180835281905260ff8c166060860152608085018b905260a085018a905290519095506001945060c080850194929350601f198201928290030190855afa158015611a23573d6000803e3d6000fd5b5050604051601f19015198975050505050505050565b604080516001600160801b031996909616602080880191909152606095861b6bffffffffffffffffffffffff1990811660308901529490951b9093166044860152605885019190915260f01b6001600160f01b03191660788401528051808403605a018152607a90930181528251928201929092206000818152600490925291902091565b6000611ac8611e65565b6000611ad78989898989611a39565b60408051606081018252925460ff81161515808552610100820463ffffffff166020860152600160281b9091046001600160801b0316918401919091529193509150611b2857600092505050610f98565b6002546000906001600160a01b03163314611b44576000611b4c565b61b4af85013a025b6040808501516000858152600460205282812080546001600160a81b031916905591519201925083917fd9b627ddaa414e8e6c82366cc9c179f6281d73968827cc17038a56852e28ac8b9190a2611ba68988836000611d8e565b5060019998505050505050505050565b600080611bc78d858a8a8a8a611df9565b90508a6001600160a01b0316816001600160a01b03161415611c0a5760ff841660021415611c0557611bfd8d8d8d8d8d88611abe565b915050611c9c565b611c9a565b8b6001600160a01b0316816001600160a01b03161415611c3e5760ff841660011415611c0557611bfd8d8d8d8d8d88611cab565b336001600160a01b038d1614611c90576040805162461bcd60e51b8152602060048201526012602482015271556e7265636f676e6973656420706172747960701b604482015290519081900360640190fd5b6000915050611c9c565b505b9b9a5050505050505050505050565b6000611cb5611e65565b6000611cc48989898989611a39565b60408051606081018252925460ff81161515808552610100820463ffffffff166020860152600160281b9091046001600160801b0316918401919091529193509150611d1557600092505050610f98565b6002546000906001600160a01b03163314611d31576000611d39565b61b5fc85013a025b6040808501516000858152600460205282812080546001600160a81b031916905591519201925083917f6eec2dd2382427616d4ea7ef183b16091feac4e2e63c8b55f25215f132df8d149190a2611ba6888883895b61271061ffff82168402046001600160801b03831601808403841015611db45750611df3565b60038054820190556040516001600160a01b0386169082860380156108fc02916000818181858888f1935050505015801561151a573d6000803e3d6000fd5b50505050565b604080516001600160801b03198089166020808401919091526001600160f81b031960f88a901b166030840152608088901b90911660318301528251602181840301815260419092019092528051910120600090611e5981868686611923565b98975050505050505050565b60408051606081018252600080825260208201819052918101919091529056fe5f627579657250657263656e74206d75737420626520313030206f72206c6f776572416d6f756e7420697320686967686572207468616e20616d6f756e7420617661696c61626c65a265627a7a7231582071306347cb3db5a0454dc3fbd33c192b2eda891ca5a1831c263b1a0c52a0b86964736f6c63430005110032
Verified Source Code Full Match
Compiler: v0.5.17+commit.d19bba13
EVM: istanbul
Optimization: Yes (200 runs)
SafeMath.sol 156 lines
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
Address.sol 70 lines
pragma solidity ^0.5.5;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Converts an `address` into `address payable`. Note that this is
* simply a type cast: the actual underlying value is not changed.
*
* _Available since v2.4.0._
*/
function toPayable(address account) internal pure returns (address payable) {
return address(uint160(account));
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*
* _Available since v2.4.0._
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-call-value
(bool success, ) = recipient.call.value(amount)("");
require(success, "Address: unable to send value, recipient may have reverted");
}
}
EthereumEscrow.sol 447 lines
pragma solidity ^0.5.17;
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract LocalCoinSwapEthereumEscrow {
/***********************
+ Global settings +
***********************/
using SafeERC20 for IERC20;
// Address of the arbitrator (currently always LocalCoinSwap staff)
address public arbitrator;
// Address of the owner (who can withdraw collected fees)
address public owner;
// Address of the relayer (who is allowed to forward signed instructions from parties)
address public relayer;
uint32 public requestCancellationMinimumTime = 2 hours;
// Cumulative balance of collected fees
uint256 public feesAvailableForWithdraw;
/***********************
+ Instruction types +
***********************/
// Seller releasing funds to the buyer
uint8 constant INSTRUCTION_RELEASE = 0x01;
// Buyer cancelling
uint8 constant INSTRUCTION_BUYER_CANCEL = 0x02;
// Seller requesting to cancel. Begins a window for buyer to object
uint8 constant INSTRUCTION_RESOLVE = 0x03;
/***********************
+ Events +
***********************/
event Created(bytes32 indexed _tradeHash);
event SellerCancelDisabled(bytes32 indexed _tradeHash);
event SellerRequestedCancel(bytes32 indexed _tradeHash);
event CancelledBySeller(bytes32 indexed _tradeHash);
event CancelledByBuyer(bytes32 indexed _tradeHash);
event Released(bytes32 indexed _tradeHash);
event DisputeResolved(bytes32 indexed _tradeHash);
struct Escrow {
// So we know the escrow exists
bool exists;
uint32 sellerCanCancelAfter;
// Cumulative cost of gas incurred by the relayer. This amount will be refunded to the owner
// in the way of fees once the escrow has completed
uint128 totalGasFeesSpentByRelayer;
}
// Mapping of active trades. The key here is a hash of the trade proprties
mapping (bytes32 => Escrow) public escrows;
modifier onlyOwner() {
require(msg.sender == owner, "Must be owner");
_;
}
modifier onlyArbitrator() {
require(msg.sender == arbitrator, "Must be arbitrator");
_;
}
constructor(address initialAddress) public {
owner = initialAddress;
arbitrator = initialAddress;
relayer = initialAddress;
}
/// @notice Create and fund a new escrow.
function createEscrow(
bytes16 _tradeID,
address _seller,
address _buyer,
uint256 _value,
uint16 _fee,
uint32 _paymentWindowInSeconds,
uint32 _expiry,
uint8 _v,
bytes32 _r,
bytes32 _s
) external payable {
// The trade hash is created by tightly-concatenating and hashing properties of the trade.
// This hash becomes the identifier of the escrow, and hence all these variables must be
// supplied on future contract calls
bytes32 _tradeHash = keccak256(abi.encodePacked(_tradeID, _seller, _buyer, _value, _fee));
// Require that trade does not already exist
require(!escrows[_tradeHash].exists, "Trade already exists");
// A signature (v, r and s) must come from localcoinswap to open an escrow
bytes32 _invitationHash = keccak256(abi.encodePacked(
_tradeHash,
_paymentWindowInSeconds,
_expiry
));
require(recoverAddress(_invitationHash, _v, _r, _s) == relayer, "Must be relayer");
// These signatures come with an expiry stamp
require(block.timestamp < _expiry, "Signature has expired"); // solium-disable-line
// Check transaction value against signed _value and make sure is not 0
require(msg.value == _value && msg.value > 0, "Incorrect ether sent");
uint32 _sellerCanCancelAfter = _paymentWindowInSeconds == 0
? 1
: uint32(block.timestamp) + _paymentWindowInSeconds; // solium-disable-line
// Add the escrow to the public mapping
escrows[_tradeHash] = Escrow(true, _sellerCanCancelAfter, 0);
emit Created(_tradeHash);
}
uint16 constant GAS_doResolveDispute = 36100;
function resolveDispute(
bytes16 _tradeID,
address payable _seller,
address payable _buyer,
uint256 _value,
uint16 _fee,
uint8 _v,
bytes32 _r,
bytes32 _s,
uint8 _buyerPercent
) external onlyArbitrator {
address _signature = recoverAddress(keccak256(abi.encodePacked(
_tradeID,
INSTRUCTION_RESOLVE
)), _v, _r, _s);
require(_signature == _buyer || _signature == _seller, "Must be buyer or seller");
Escrow memory _escrow;
bytes32 _tradeHash;
(_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
require(_escrow.exists, "Escrow does not exist");
require(_buyerPercent <= 100, "_buyerPercent must be 100 or lower");
uint256 _totalFees = _escrow.totalGasFeesSpentByRelayer + (GAS_doResolveDispute * uint128(tx.gasprice));
require(_value - _totalFees <= _value, "Overflow error"); // Prevent underflow
feesAvailableForWithdraw += _totalFees; // Add the the pot for localcoinswap to withdraw
delete escrows[_tradeHash];
emit DisputeResolved(_tradeHash);
if (_buyerPercent > 0) {
// Take fees if buyer wins dispute
uint256 _escrowFees = (_value * _fee / 10000);
// Prevent underflow
uint256 _buyerAmount = _value * _buyerPercent / 100 - _totalFees - _escrowFees;
require(_buyerAmount <= _value, "Overflow error");
feesAvailableForWithdraw += _escrowFees;
_buyer.transfer(_buyerAmount);
}
if (_buyerPercent < 100) {
_seller.transfer((_value - _totalFees) * (100 - _buyerPercent) / 100);
}
}
function release(
bytes16 _tradeID,
address payable _seller,
address payable _buyer,
uint256 _value,
uint16 _fee
) external returns (bool){
require(msg.sender == _seller, "Must be seller");
return doRelease(_tradeID, _seller, _buyer, _value, _fee, 0);
}
function buyerCancel(
bytes16 _tradeID,
address payable _seller,
address payable _buyer,
uint256 _value,
uint16 _fee
) external returns (bool) {
require(msg.sender == _buyer, "Must be buyer");
return doBuyerCancel(_tradeID, _seller, _buyer, _value, _fee, 0);
}
uint16 constant GAS_batchRelayBaseCost = 28500;
function batchRelay(
bytes16[] memory _tradeID,
address payable[] memory _seller,
address payable[] memory _buyer,
uint256[] memory _value,
uint16[] memory _fee,
uint128[] memory _maximumGasPrice,
uint8[] memory _v,
bytes32[] memory _r,
bytes32[] memory _s,
uint8[] memory _instructionByte
) public returns (bool[] memory) {
bool[] memory _results = new bool[](_tradeID.length);
uint128 _additionalGas = uint128(msg.sender == relayer ? GAS_batchRelayBaseCost / _tradeID.length : 0);
for (uint8 i = 0; i < _tradeID.length; i++) {
_results[i] = relay(
_tradeID[i],
_seller[i],
_buyer[i],
_value[i],
_fee[i],
_maximumGasPrice[i],
_v[i],
_r[i],
_s[i],
_instructionByte[i],
_additionalGas
);
}
return _results;
}
/// @notice Withdraw fees collected by the contract. Only the owner can call this.
/// @param _to Address to withdraw fees in to
/// @param _amount Amount to withdraw
function withdrawFees(address payable _to, uint256 _amount) external onlyOwner {
// This check also prevents underflow
require(_amount <= feesAvailableForWithdraw, "Amount is higher than amount available");
feesAvailableForWithdraw -= _amount;
_to.transfer(_amount);
}
/// @notice Set the arbitrator to a new address. Only the owner can call this.
/// @param _newArbitrator Address of the replacement arbitrator
function setArbitrator(address _newArbitrator) external onlyOwner {
arbitrator = _newArbitrator;
}
/// @notice Change the owner to a new address.
function setOwner(address _newOwner) external onlyOwner {
owner = _newOwner;
}
/// @notice Change the relayer to a new address.
function setRelayer(address _newRelayer) external onlyOwner {
relayer = _newRelayer;
}
/// @notice Allows the owner to withdraw stuck ERC20 tokens.
function transferToken(
IERC20 TokenContract,
address _transferTo,
uint256 _value
) external onlyOwner {
TokenContract.transfer(_transferTo, _value);
}
/// @notice Allows the owner to withdraw stuck ERC20 tokens.
function transferTokenFrom(
IERC20 TokenContract,
address _transferTo,
address _transferFrom,
uint256 _value
) external onlyOwner {
TokenContract.transferFrom(_transferTo, _transferFrom, _value);
}
/// @notice Allows the owner to withdraw stuck ERC20 tokens.
function approveToken(
IERC20 TokenContract,
address _spender,
uint256 _value
) external onlyOwner {
TokenContract.approve(_spender, _value);
}
function relay(
bytes16 _tradeID,
address payable _seller,
address payable _buyer,
uint256 _value,
uint16 _fee,
uint128 _maximumGasPrice,
uint8 _v,
bytes32 _r,
bytes32 _s,
uint8 _instructionByte,
uint128 _additionalGas
) private returns (bool) {
address _relayedSender = getRelayedSender(
_tradeID,
_instructionByte,
_maximumGasPrice,
_v,
_r,
_s
);
if (_relayedSender == _buyer) {
// Buyer's instructions:
if (_instructionByte == INSTRUCTION_BUYER_CANCEL) {
// Cancel
return doBuyerCancel(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
}
} else if (_relayedSender == _seller) {
// Seller's instructions:
if (_instructionByte == INSTRUCTION_RELEASE) {
// Release
return doRelease(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
}
} else {
require(msg.sender == _seller, "Unrecognised party");
return false;
}
}
/// @notice Increase the amount of gas to be charged later on completion of an escrow
function increaseGasSpent(bytes32 _tradeHash, uint128 _gas) private {
escrows[_tradeHash].totalGasFeesSpentByRelayer += _gas * uint128(tx.gasprice);
}
/// @notice Transfer the value of an escrow, minus the fees, minus the gas costs incurred by relay
function transferMinusFees(
address payable _to,
uint256 _value,
uint128 _totalGasFeesSpentByRelayer,
uint16 _fee
) private {
uint256 _totalFees = (_value * _fee / 10000) + _totalGasFeesSpentByRelayer;
// Prevent underflow
if(_value - _totalFees > _value) {
return;
}
// Add fees to the pot for localcoinswap to withdraw
feesAvailableForWithdraw += _totalFees;
_to.transfer(_value - _totalFees);
}
uint16 constant GAS_doRelease = 46588;
function doRelease(
bytes16 _tradeID,
address payable _seller,
address payable _buyer,
uint256 _value,
uint16 _fee,
uint128 _additionalGas
) private returns (bool) {
Escrow memory _escrow;
bytes32 _tradeHash;
(_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
if (!_escrow.exists) return false;
uint128 _gasFees = _escrow.totalGasFeesSpentByRelayer + (msg.sender == relayer
? (GAS_doRelease + _additionalGas ) * uint128(tx.gasprice)
: 0
);
delete escrows[_tradeHash];
emit Released(_tradeHash);
transferMinusFees(_buyer, _value, _gasFees, _fee);
return true;
}
uint16 constant GAS_doBuyerCancel = 46255;
function doBuyerCancel(
bytes16 _tradeID,
address payable _seller,
address payable _buyer,
uint256 _value,
uint16 _fee,
uint128 _additionalGas
) private returns (bool) {
Escrow memory _escrow;
bytes32 _tradeHash;
(_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
if (!_escrow.exists) {
return false;
}
uint128 _gasFees = _escrow.totalGasFeesSpentByRelayer + (msg.sender == relayer
? (GAS_doBuyerCancel + _additionalGas ) * uint128(tx.gasprice)
: 0
);
delete escrows[_tradeHash];
emit CancelledByBuyer(_tradeHash);
transferMinusFees(_seller, _value, _gasFees, 0);
return true;
}
uint16 constant GAS_doSellerRequestCancel = 29507;
function doSellerRequestCancel(
bytes16 _tradeID,
address _seller,
address _buyer,
uint256 _value,
uint16 _fee,
uint128 _additionalGas
) private returns (bool) {
// Called on unlimited payment window trades where the buyer is not responding
Escrow memory _escrow;
bytes32 _tradeHash;
(_escrow, _tradeHash) = getEscrowAndHash(_tradeID, _seller, _buyer, _value, _fee);
if (!_escrow.exists) {
return false;
}
if(_escrow.sellerCanCancelAfter != 1) {
return false;
}
escrows[_tradeHash].sellerCanCancelAfter = uint32(block.timestamp) // solium-disable-line
+ requestCancellationMinimumTime;
emit SellerRequestedCancel(_tradeHash);
if (msg.sender == relayer) {
increaseGasSpent(_tradeHash, GAS_doSellerRequestCancel + _additionalGas);
}
return true;
}
function getRelayedSender(
bytes16 _tradeID,
uint8 _instructionByte,
uint128 _maximumGasPrice,
uint8 _v,
bytes32 _r,
bytes32 _s
) private pure returns (address) {
bytes32 _hash = keccak256(abi.encodePacked(
_tradeID,
_instructionByte,
_maximumGasPrice
));
return recoverAddress(_hash, _v, _r, _s);
}
function getEscrowAndHash(
bytes16 _tradeID,
address _seller,
address _buyer,
uint256 _value,
uint16 _fee
) private view returns (Escrow storage, bytes32) {
bytes32 _tradeHash = keccak256(abi.encodePacked(
_tradeID,
_seller,
_buyer,
_value,
_fee
));
return (escrows[_tradeHash], _tradeHash);
}
function recoverAddress(
bytes32 _h,
uint8 _v,
bytes32 _r,
bytes32 _s
) private pure returns (address) {
bytes memory _prefix = "\x19Ethereum Signed Message:\n32";
bytes32 _prefixedHash = keccak256(abi.encodePacked(_prefix, _h));
return ecrecover(_prefixedHash, _v, _r, _s);
}
}
IERC20.sol 76 lines
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see {ERC20Detailed}.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
SafeERC20.sol 75 lines
pragma solidity ^0.5.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Read Contract
arbitrator 0x6cc6cde1 → address
escrows 0x2d83549c → bool, uint32, uint128
feesAvailableForWithdraw 0xde5785d5 → uint256
owner 0x8da5cb5b → address
relayer 0x8406c079 → address
requestCancellationMinimumTime 0x57938b2a → uint32
Write Contract 12 functions
These functions modify contract state and require a wallet transaction to execute.
approveToken 0xda3e3397
address TokenContract
address _spender
uint256 _value
batchRelay 0x8eb4e0ad
bytes16[] _tradeID
address[] _seller
address[] _buyer
uint256[] _value
uint16[] _fee
uint128[] _maximumGasPrice
uint8[] _v
bytes32[] _r
bytes32[] _s
uint8[] _instructionByte
returns: bool[]
buyerCancel 0x2cc9636c
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
returns: bool
createEscrow 0xf1e03d67
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
uint32 _paymentWindowInSeconds
uint32 _expiry
uint8 _v
bytes32 _r
bytes32 _s
release 0xe9600f12
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
returns: bool
resolveDispute 0x24943c7d
bytes16 _tradeID
address _seller
address _buyer
uint256 _value
uint16 _fee
uint8 _v
bytes32 _r
bytes32 _s
uint8 _buyerPercent
setArbitrator 0xb0eefabe
address _newArbitrator
setOwner 0x13af4035
address _newOwner
setRelayer 0x6548e9bc
address _newRelayer
transferToken 0xf5537ede
address TokenContract
address _transferTo
uint256 _value
transferTokenFrom 0xe5994905
address TokenContract
address _transferTo
address _transferFrom
uint256 _value
withdrawFees 0xad3b1b47
address _to
uint256 _amount
Top Interactions
| Address | Txns | Sent | Received |
|---|---|---|---|
| 0xB2dDC63d...bAfE | 1 | 1 | |
| 0x877cf5F0...5ce5 | 1 | 1 |
Token Balances (1)
View Transfers →Recent Transactions
|
| Hash | Block | Age | From/To | Value | |
|---|---|---|---|---|---|
| 0x51e0ea6b...1f2b7a | 24,417,347 | IN | 0x877cf5F0...5ce5 | 0 ETH | |
| 0x3ffb4511...1c3152 | 24,417,337 | IN | 0xB2dDC63d...bAfE | 0.088747 ETH |