added approve and call gas relayed for ERC20
This commit is contained in:
parent
fe4a10dfcd
commit
4c5cb43da0
|
@ -11,11 +11,12 @@ import "../token/ERC20Token.sol";
|
||||||
contract IdentityGasRelay is Identity {
|
contract IdentityGasRelay is Identity {
|
||||||
|
|
||||||
bytes4 public constant CALL_PREFIX = bytes4(keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)"));
|
bytes4 public constant CALL_PREFIX = bytes4(keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)"));
|
||||||
|
bytes4 public constant APPROVEANDCALL_PREFIX = bytes4(keccak256("approveAndCallGasRelay(address,address,uint256,bytes32,uint256,uint256)"));
|
||||||
|
|
||||||
event ExecutedGasRelayed(bytes32 signHash, bool success);
|
event ExecutedGasRelayed(bytes32 signHash, bool success);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice include ethereum signed callHash in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
|
* @notice include ethereum signed callHash in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
|
||||||
* allows identity of being controlled without requiring ether in key balace
|
* allows identity of being controlled without requiring ether in key balace
|
||||||
* @param _to destination of call
|
* @param _to destination of call
|
||||||
* @param _value call value (ether)
|
* @param _value call value (ether)
|
||||||
|
@ -83,6 +84,82 @@ contract IdentityGasRelay is Identity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice include ethereum signed approve ERC20 and call hash
|
||||||
|
* (`ERC20Token(baseToken).approve(_to, _value)` + `_to.call(_data)`).
|
||||||
|
* in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
|
||||||
|
* fixes race condition in double transaction for ERC20.
|
||||||
|
* @param _baseToken token approved for `_to`
|
||||||
|
* @param _to destination of call
|
||||||
|
* @param _value call value (ether)
|
||||||
|
* @param _data call data
|
||||||
|
* @param _nonce current identity nonce
|
||||||
|
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
|
||||||
|
* @param _gasMinimal minimal amount of gas needed to complete the execution
|
||||||
|
* @param _gasToken token being used for paying `msg.sender`
|
||||||
|
* @param _messageSignatures rsv concatenated ethereum signed message signatures required
|
||||||
|
*/
|
||||||
|
function approveAndCallGasRelayed(
|
||||||
|
address _baseToken,
|
||||||
|
address _to,
|
||||||
|
uint256 _value,
|
||||||
|
bytes _data,
|
||||||
|
uint _nonce,
|
||||||
|
uint _gasPrice,
|
||||||
|
uint _gasMinimal,
|
||||||
|
address _gasToken,
|
||||||
|
bytes _messageSignatures
|
||||||
|
)
|
||||||
|
external
|
||||||
|
{
|
||||||
|
//verify transaction parameters
|
||||||
|
require(_nonce == nonce);
|
||||||
|
uint startGas = gasleft();
|
||||||
|
require(startGas >= _gasMinimal);
|
||||||
|
require(_baseToken != address(0)); //_baseToken should be something!
|
||||||
|
require(_to != address(this)); //no management with approveAndCall
|
||||||
|
|
||||||
|
// calculates signHash
|
||||||
|
bytes32 signHash = getSignHash(
|
||||||
|
approveAndCallGasRelayHash(
|
||||||
|
_baseToken,
|
||||||
|
_to,
|
||||||
|
_value,
|
||||||
|
keccak256(_data),
|
||||||
|
_nonce,
|
||||||
|
_gasPrice,
|
||||||
|
_gasMinimal,
|
||||||
|
_gasToken
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
//verify if signatures are valid and came from correct actors;
|
||||||
|
verifySignatures(
|
||||||
|
ACTION_KEY, //no management with approveAndCall
|
||||||
|
signHash,
|
||||||
|
_messageSignatures
|
||||||
|
);
|
||||||
|
|
||||||
|
approveAndCall(
|
||||||
|
signHash,
|
||||||
|
_baseToken,
|
||||||
|
_to,
|
||||||
|
_value,
|
||||||
|
_data
|
||||||
|
);
|
||||||
|
|
||||||
|
//refund gas used using contract held ERC20 tokens or ETH
|
||||||
|
if (_gasPrice > 0) {
|
||||||
|
uint256 _amount = 21000 + (startGas - gasleft());
|
||||||
|
_amount = _amount * _gasPrice;
|
||||||
|
if (_gasToken == address(0)) {
|
||||||
|
address(msg.sender).transfer(_amount);
|
||||||
|
} else {
|
||||||
|
ERC20Token(_gasToken).transfer(msg.sender, _amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice reverts if signatures are not valid for the signed hash and required key type.
|
* @notice reverts if signatures are not valid for the signed hash and required key type.
|
||||||
|
@ -154,6 +231,46 @@ contract IdentityGasRelay is Identity {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @notice get callHash
|
||||||
|
* @param _to destination of call
|
||||||
|
* @param _value call value (ether)
|
||||||
|
* @param _dataHash call data hash
|
||||||
|
* @param _nonce current identity nonce
|
||||||
|
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
|
||||||
|
* @param _gasMinimal minimal amount of gas needed to complete the execution
|
||||||
|
* @param _gasToken token being used for paying `msg.sender`
|
||||||
|
* @return callGasRelayHash the hash to be signed by wallet
|
||||||
|
*/
|
||||||
|
function approveAndCallGasRelayHash(
|
||||||
|
address _baseToken,
|
||||||
|
address _to,
|
||||||
|
uint256 _value,
|
||||||
|
bytes32 _dataHash,
|
||||||
|
uint _nonce,
|
||||||
|
uint256 _gasPrice,
|
||||||
|
uint256 _gasMinimal,
|
||||||
|
address _gasToken
|
||||||
|
)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (bytes32 _callGasRelayHash)
|
||||||
|
{
|
||||||
|
_callGasRelayHash = keccak256(
|
||||||
|
address(this),
|
||||||
|
APPROVEANDCALL_PREFIX,
|
||||||
|
_baseToken,
|
||||||
|
_to,
|
||||||
|
_value,
|
||||||
|
_dataHash,
|
||||||
|
_nonce,
|
||||||
|
_gasPrice,
|
||||||
|
_gasMinimal,
|
||||||
|
_gasToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @notice Hash a hash with `"\x19Ethereum Signed Message:\n32"`
|
* @notice Hash a hash with `"\x19Ethereum Signed Message:\n32"`
|
||||||
* @param _hash Sign to hash.
|
* @param _hash Sign to hash.
|
||||||
|
@ -226,4 +343,23 @@ contract IdentityGasRelay is Identity {
|
||||||
require(v == 27 || v == 28);
|
require(v == 27 || v == 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function approveAndCall(
|
||||||
|
bytes32 _signHash,
|
||||||
|
address _token,
|
||||||
|
address _to,
|
||||||
|
uint256 _value,
|
||||||
|
bytes _data
|
||||||
|
)
|
||||||
|
private
|
||||||
|
{
|
||||||
|
//executes transaction
|
||||||
|
nonce++;
|
||||||
|
ERC20Token(_token).approve(_to, _value);
|
||||||
|
emit ExecutedGasRelayed(
|
||||||
|
_signHash,
|
||||||
|
_to.call(_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue