Contract Name:
LocalCoinSwapDaiEscrow
Contract Source Code:
File 1 of 1 : LocalCoinSwapDaiEscrow
/**
* Tether trading contract
*/
pragma solidity ^0.5.0;
contract DaiERC20 {
function transfer(address _to, uint _value) public returns (bool success);
function transferFrom(address _from, address _to, uint _value) public returns (bool success);
function approve(address _spender, uint _value) public returns (bool success);
}
contract LocalCoinSwapDaiEscrow {
/***********************
+ Global settings +
***********************/
address public arbitrator;
address public owner;
address public relayer;
uint256 public feesAvailableForWithdraw;
// The contract address of the ERC20 token handled by this smart contract, can only be set once
DaiERC20 public tokenContract;
// The minimum value under which we will not accept the creation of escrow
uint16 public minimumValue = 1;
uint32 public requestCancellationMinimumTime = 2 hours;
/***********************
+ Escrow Structure +
***********************/
struct Escrow {
// Set so we know the trade has already been created
bool exists;
uint32 sellerCanCancelAfter;
// The total cost of gas spent by relaying parties. This amount will be
// emmitted to us once the escrow is finished for accounting purposes.
uint128 totalGasFeesSpentByRelayer;
}
// Mapping of active trades. Key is a hash of the trade data
mapping (bytes32 => Escrow) public escrows;
/***********************
+ Instruction types +
***********************/
// Called when the buyer marks payment as sent. Locks funds in escrow
uint8 constant INSTRUCTION_SELLER_CANNOT_CANCEL = 0x01;
// Buyer cancelling
uint8 constant INSTRUCTION_BUYER_CANCEL = 0x02;
// Seller cancelling
uint8 constant INSTRUCTION_SELLER_CANCEL = 0x03;
// Seller requesting to cancel. Begins a window for buyer to object
uint8 constant INSTRUCTION_SELLER_REQUEST_CANCEL = 0x04;
// Seller releasing funds to the buyer
uint8 constant INSTRUCTION_RELEASE = 0x05;
// Either party permitting the arbitrator to resolve a dispute
uint8 constant INSTRUCTION_RESOLVE = 0x06;
/***********************
+ Events +
***********************/
event Created(bytes32 _tradeHash);
event SellerCancelDisabled(bytes32 _tradeHash);
event SellerRequestedCancel(bytes32 _tradeHash);
event CancelledBySeller(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);
event CancelledByBuyer(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);
event Released(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);
event DisputeResolved(bytes32 _tradeHash, uint128 totalGasFeesSpentByRelayer);
/***********************
+ Constructor +
***********************/
constructor(address initialAddress, DaiERC20 daiAddress) public {
owner = initialAddress;
arbitrator = initialAddress;
relayer = initialAddress;
tokenContract = daiAddress;
}
/***********************
+ Handle Trades +
***********************/
/// @notice Create and fund a new escrow.
/// @param _tradeID The unique ID of the trade, generated by localcoinswap.com
/// @param _seller The selling party
/// @param _buyer The buying party
/// @param _value The amount of the escrow, exclusive of the fee
/// @param _fee localcoinswap's commission in 1/10000ths
/// @param _paymentWindowInSeconds The time in seconds from escrow creation that the seller can cancel after
/// @param _expiry This transaction must be created before this time
/// @param _v Signature "v" component
/// @param _r Signature "r" component
/// @param _s Signature "s" component
function createEscrow(
/**
* Create a new escrow and add it to `escrows`.
* _tradeHash is created by hashing _tradeID, _seller, _buyer, _value and _fee variables. These variables must be supplied on future contract calls.
* v, r and s is the signature data supplied from the api. The sig is keccak256(_tradeHash, _paymentWindowInSeconds, _expiry).
*/
bytes16 _tradeID, // The unique ID of the trade, generated by us
address _seller, // The selling party of the trade
address _buyer, // The buying party of the trade
uint256 _value, // The token amount being held in escrow
uint16 _fee, // Our fee in 1/10000ths of a token
uint32 _paymentWindowInSeconds, // The time in seconds from contract creation that the buyer has to mark as paid
uint32 _expiry, // Provided by us. This transaction must be created before this time.
uint8 _v, // Signature value
bytes32 _r, // Signature value
bytes32 _s // Signature value
) external payable {
bytes32 _tradeHash = keccak256(abi.encodePacked(_tradeID, _seller, _buyer, _value, _fee));
require(!escrows[_tradeHash].exists, "Trade already exists in escrow mapping");
bytes32 _invitationHash = keccak256(abi.encodePacked(
_tradeHash,
_paymentWindowInSeconds,
_expiry
));
require(_value > minimumValue, "Escrow value must be greater than minimum value"); // Check escrow value is greater than minimum value
require(block.timestamp < _expiry, "Trade has already expired"); // solium-disable-line
require(recoverAddress(_invitationHash, _v, _r, _s) == relayer, "Transaction signature did not come from relayer");
tokenContract.transferFrom(msg.sender, address(this), _value);
uint32 _sellerCanCancelAfter = _paymentWindowInSeconds == 0 ? 1 : uint32(block.timestamp) + _paymentWindowInSeconds; // solium-disable-line
escrows[_tradeHash] = Escrow(true, _sellerCanCancelAfter, 0);
emit Created(_tradeHash);
}
/// @notice Release ether in escrow to the buyer. Direct call option.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @return bool
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);
}
uint16 constant GAS_doRelease = 46588;
/// @notice Release escrow to the buyer. This completes it and removes it from the mapping.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _additionalGas Additional gas to be deducted after this operation
/// @return bool
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, _gasFees);
transferMinusFees(_buyer, _value, _fee);
return true;
}
uint16 constant GAS_doResolveDispute = 36100;
/// @notice Called by the arbitrator to resolve a dispute. Requires a signature from either party.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _v Signature "v" component
/// @param _r Signature "r" component
/// @param _s Signature "s" component
/// @param _buyerPercent What % should be distributed to the buyer (this is usually 0 or 100)
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");
_escrow.totalGasFeesSpentByRelayer += (GAS_doResolveDispute * uint128(tx.gasprice));
delete escrows[_tradeHash];
emit DisputeResolved(_tradeHash, _escrow.totalGasFeesSpentByRelayer);
if (_buyerPercent > 0) {
// If dispute goes to buyer take the fee
uint256 _totalFees = (_value * _fee / 10000);
// Prevent underflow
require(_value * _buyerPercent / 100 - _totalFees <= _value, "Overflow error");
feesAvailableForWithdraw += _totalFees;
tokenContract.transfer(_buyer, _value * _buyerPercent / 100 - _totalFees);
}
if (_buyerPercent < 100) {
tokenContract.transfer(_seller, _value * (100 - _buyerPercent) / 100);
}
}
/// @notice Disable the seller from cancelling (i.e. "mark as paid"). Direct call option.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @return bool
function disableSellerCancel(
bytes16 _tradeID,
address _seller,
address _buyer,
uint256 _value,
uint16 _fee
) external returns (bool) {
require(msg.sender == _buyer, "Must be buyer");
return doDisableSellerCancel(_tradeID, _seller, _buyer, _value, _fee, 0);
}
/// @notice Cancel the escrow as a buyer. Direct call option.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @return bool
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);
}
/// @notice Request to cancel as a seller. Direct call option.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @return bool
function sellerRequestCancel(
bytes16 _tradeID,
address _seller,
address _buyer,
uint256 _value,
uint16 _fee
) external returns (bool) {
require(msg.sender == _seller, "Must be seller");
return doSellerRequestCancel(_tradeID, _seller, _buyer, _value, _fee, 0);
}
/// @notice Increase the amount of gas used during the trade, tracking is for accounting purposes
/// @param _tradeHash Trade hash
/// @param _gas Gas cost
function increaseGasSpent(bytes32 _tradeHash, uint128 _gas) private {
escrows[_tradeHash].totalGasFeesSpentByRelayer += _gas * uint128(tx.gasprice);
}
/// @notice Transfer the value of an escrow, minus the fees. We do not explicity handle gas costs of relayer
/// @param _to Recipient address
/// @param _value Value of the transfer
/// @param _fee Commission in 1/10000ths
function transferMinusFees(
address payable _to,
uint256 _value,
uint16 _fee
) private {
uint256 _totalFees = (_value * _fee / 10000);
// Prevent underflow
if(_value - _totalFees > _value) {
return;
}
// Add fees to the pot for localcoinswap to withdraw
feesAvailableForWithdraw += _totalFees;
tokenContract.transfer(_to, _value - _totalFees);
}
uint16 constant GAS_doDisableSellerCancel = 28944;
/// @notice Prevents the seller from cancelling an escrow. Used to "mark as paid" by the buyer.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _additionalGas Additional gas to be deducted after this operation
/// @return bool
function doDisableSellerCancel(
bytes16 _tradeID,
address _seller,
address _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;
if(_escrow.sellerCanCancelAfter == 0) return false;
escrows[_tradeHash].sellerCanCancelAfter = 0;
emit SellerCancelDisabled(_tradeHash);
if (msg.sender == relayer) {
increaseGasSpent(_tradeHash, GAS_doDisableSellerCancel + _additionalGas);
}
return true;
}
uint16 constant GAS_doBuyerCancel = 46255;
/// @notice Cancels the trade and returns the ether to the seller. Can only be called the buyer.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _additionalGas Additional gas to be deducted after this operation
/// @return bool
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);
require(_escrow.exists, "Escrow does not exist");
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, _gasFees);
transferMinusFees(_seller, _value, 0);
return true;
}
uint16 constant GAS_doSellerCancel = 46815;
/// @notice Returns the ether in escrow to the seller. Called by the seller. Sometimes unavailable.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _additionalGas Additional gas to be deducted after this operation
/// @return bool
function doSellerCancel(
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;
}
if(_escrow.sellerCanCancelAfter <= 1 || _escrow.sellerCanCancelAfter > block.timestamp) { // solium-disable-line
return false;
}
uint128 _gasFees = _escrow.totalGasFeesSpentByRelayer + (msg.sender == relayer
? (GAS_doSellerCancel + _additionalGas ) * uint128(tx.gasprice)
: 0
);
delete escrows[_tradeHash];
emit CancelledBySeller(_tradeHash, _gasFees);
transferMinusFees(_seller, _value, 0);
return true;
}
uint16 constant GAS_doSellerRequestCancel = 29507;
/// @notice Request to cancel. Used if the buyer is unresponsive. Begins a countdown timer.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _additionalGas Additional gas to be deducted after this operation
/// @return bool
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;
}
/***********************
+ Relays +
***********************/
/// @notice Relay multiple signed instructions from parties of escrows.
/// @param _tradeID List of _tradeID values
/// @param _seller List of _seller values
/// @param _buyer List of _buyer values
/// @param _value List of _value values
/// @param _fee List of _fee values
/// @param _maximumGasPrice List of _maximumGasPrice values
/// @param _v List of signature "v" components
/// @param _r List of signature "r" components
/// @param _s List of signature "s" components
/// @param _instructionByte List of _instructionByte values
/// @return bool List of results
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 Relay a signed instruction from a party of an escrow.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @param _maximumGasPrice Maximum gas price permitted for the relayer (set by the instructor)
/// @param _v Signature "v" component
/// @param _r Signature "r" component
/// @param _s Signature "s" component
/// @param _additionalGas Additional gas to be deducted after this operation
/// @return bool
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_SELLER_CANNOT_CANCEL) {
// Disable seller from cancelling
return doDisableSellerCancel(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
} else 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 if (_instructionByte == INSTRUCTION_SELLER_CANCEL) {
// Cancel
return doSellerCancel(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
} else if (_instructionByte == INSTRUCTION_SELLER_REQUEST_CANCEL){
// Request to cancel
return doSellerRequestCancel(_tradeID, _seller, _buyer, _value, _fee, _additionalGas);
}
} else {
require(msg.sender == _seller, "Unrecognised party");
return false;
}
}
/***********************
+ Setters +
***********************/
/// @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 {
/**
* Set the arbitrator to a new address. Only the owner can call this.
* @param address _newArbitrator
*/
arbitrator = _newArbitrator;
}
/// @notice Change the owner to a new address. Only the owner can call this.
/// @param _newOwner Address of the replacement owner
function setOwner(address _newOwner) external onlyOwner {
/**
* Change the owner to a new address. Only the owner can call this.
* @param address _newOwner
*/
owner = _newOwner;
}
/// @notice Change the relayer to a new address. Only the owner can call this.
/// @param _newRelayer Address of the replacement relayer
function setRelayer(address _newRelayer) external onlyOwner {
/**
* Change the relayer to a new address. Only the owner can call this.
* @param address _newRelayer
*/
relayer = _newRelayer;
}
/// @notice Change the minimum escrow value. Only the owner can call this.
/// @param _newMinimumValue uint16 of the new minimum value
function setMinimumValue(uint16 _newMinimumValue) external onlyOwner {
/**
* Change the value to a new minimum value. Only the owner can call this.
* @param uint16 _newMinimumValue
*/
minimumValue = _newMinimumValue;
}
/// @notice Change the requestCancellationMinimumTime. Only the owner can call this.
/// @param _newRequestCancellationMinimumTime Replacement
function setRequestCancellationMinimumTime(uint32 _newRequestCancellationMinimumTime) external onlyOwner {
/**
* Change the requestCancellationMinimumTime. Only the owner can call this.
* @param uint32 _newRequestCancellationMinimumTime
*/
requestCancellationMinimumTime = _newRequestCancellationMinimumTime;
}
/***********************
+ Helper Functions +
***********************/
/// @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;
tokenContract.transfer(_to, _amount);
}
/// @notice Hashes the values and returns the matching escrow object and trade hash.
/// @dev Returns an empty escrow struct and 0 _tradeHash if not found.
/// @param _tradeID Escrow "tradeID" parameter
/// @param _seller Escrow "seller" parameter
/// @param _buyer Escrow "buyer" parameter
/// @param _value Escrow "value" parameter
/// @param _fee Escrow "fee parameter
/// @return Escrow
function getEscrowAndHash(
/**
* Hashes the values and returns the matching escrow object and trade hash.
* Returns an empty escrow struct and 0 _tradeHash if not found
*/
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);
}
/// @notice Returns an empty escrow struct and 0 _tradeHash if not found.
/// @param _h Data to be hashed
/// @param _v Signature "v" component
/// @param _r Signature "r" component
/// @param _s Signature "s" component
/// @return address
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);
}
/// @notice Get the sender of the signed instruction.
/// @param _tradeID Identifier of the trade
/// @param _instructionByte Identifier of the instruction
/// @param _maximumGasPrice Maximum gas price permitted by the sender
/// @param _v Signature "v" component
/// @param _r Signature "r" component
/// @param _s Signature "s" component
/// @return address
function getRelayedSender(
bytes16 _tradeID, // The unique ID of the trade, generated by us
uint8 _instructionByte, // The desired action of the user, matching an ACTION_* constant
uint128 _maximumGasPrice, // The maximum gas price the user is willing to pay
uint8 _v, // Signature value
bytes32 _r, // Signature value
bytes32 _s // Signature value
) private view returns (address) {
bytes32 _hash = keccak256(abi.encodePacked(_tradeID, _instructionByte, _maximumGasPrice));
require(tx.gasprice < _maximumGasPrice, "Gas price is higher than maximum gas price");
return recoverAddress(_hash, _v, _r, _s);
}
/// @notice Send ERC20 tokens away. This function allows the owner to withdraw stuck ERC20 tokens.
/// @param _tokenContract Token contract
/// @param _transferTo Recipient
/// @param _value Value
function transferToken(DaiERC20 _tokenContract, address _transferTo, uint256 _value) external onlyOwner {
/**
* If ERC20 tokens are sent to this contract, they will be trapped forever.
* This function is way for us to withdraw them so we can get them back to their rightful owner
*/
_tokenContract.transfer(_transferTo, _value);
}
/// @notice Send ERC20 tokens away. This function allows the owner to withdraw stuck ERC20 tokens.
/// @param _tokenContract Token contract
/// @param _transferTo Recipient
/// @param _transferFrom Sender
/// @param _value Value
function transferTokenFrom(DaiERC20 _tokenContract, address _transferTo, address _transferFrom, uint256 _value) external onlyOwner {
/**
* If ERC20 tokens are sent to this contract, they will be trapped forever.
* This function is way for us to withdraw them so we can get them back to their rightful owner
*/
_tokenContract.transferFrom(_transferTo, _transferFrom, _value);
}
/// @notice Send ERC20 tokens away. This function allows the owner to withdraw stuck ERC20 tokens.
/// @param _tokenContract Token contract
/// @param _spender Spender address
/// @param _value Value
function approveToken(DaiERC20 _tokenContract, address _spender, uint256 _value) external onlyOwner {
/**
* If ERC20 tokens are sent to this contract, they will be trapped forever.
* This function is way for us to withdraw them so we can get them back to their rightful owner
*/
_tokenContract.approve(_spender, _value);
}
modifier onlyOwner() {
require(msg.sender == owner, "Only the current owner can change the owner");
_;
}
modifier onlyArbitrator() {
require(msg.sender == arbitrator, "Only the current owner can change the arbitrator");
_;
}
}