kill zombie code, fix conventions, fix approveAndCall, allow create fail
This commit is contained in:
parent
0683317821
commit
0f9c233657
|
@ -11,63 +11,19 @@ import "../token/ERC20Token.sol";
|
|||
*/
|
||||
contract IdentityGasRelay is Identity {
|
||||
|
||||
bytes4 public constant MSG_CALL_PREFIX = bytes4(keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)"));
|
||||
bytes4 public constant MSG_DEPLOY_PREFIX = bytes4(keccak256("deployGasRelay(uint256,bytes32,uint256,uint256,address)"));
|
||||
bytes4 public constant MSG_APPROVEANDCALL_PREFIX = bytes4(keccak256("approveAndCallGasRelay(address,address,uint256,bytes32,uint256,uint256)"));
|
||||
bytes4 public constant MSG_CALL_PREFIX = bytes4(
|
||||
keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)")
|
||||
);
|
||||
bytes4 public constant MSG_DEPLOY_PREFIX = bytes4(
|
||||
keccak256("deployGasRelay(uint256,bytes32,uint256,uint256,address)")
|
||||
);
|
||||
bytes4 public constant MSG_APPROVEANDCALL_PREFIX = bytes4(
|
||||
keccak256("approveAndCallGasRelay(address,address,uint256,bytes32,uint256,uint256)")
|
||||
);
|
||||
|
||||
event ExecutedGasRelayed(bytes32 messageHash);
|
||||
event ContractDeployed(address deployedAddress);
|
||||
|
||||
/**
|
||||
* @param _messageHash that is signed
|
||||
* @param _requiredPurpose key purpose for this type of call
|
||||
* @param _nonce current identity nonce
|
||||
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
|
||||
* @param _gasLimit minimal gasLimit required to execute this call
|
||||
* @param _gasToken token being used for paying `msg.sender`
|
||||
* @param _messageSignatures rsv concatenated ethereum signed message signatures required
|
||||
*/
|
||||
modifier executeGasRelayed (
|
||||
bytes32 _messageHash,
|
||||
uint256 _requiredPurpose,
|
||||
uint _nonce,
|
||||
uint _gasPrice,
|
||||
uint _gasLimit,
|
||||
address _gasToken,
|
||||
bytes _messageSignatures
|
||||
) {
|
||||
//query current gas available
|
||||
uint startGas = gasleft();
|
||||
|
||||
//verify transaction parameters
|
||||
require(startGas >= _gasLimit);
|
||||
require(_nonce == nonce);
|
||||
|
||||
//verify if signatures are valid and came from correct actors;
|
||||
verifySignatures(
|
||||
_requiredPurpose,
|
||||
_messageHash,
|
||||
_messageSignatures
|
||||
);
|
||||
|
||||
//increase nonce
|
||||
nonce++;
|
||||
|
||||
//executes transaction
|
||||
_;
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
bytes32[] _keys,
|
||||
uint256[] _purposes,
|
||||
|
@ -120,7 +76,7 @@ contract IdentityGasRelay is Identity {
|
|||
|
||||
//verify transaction parameters
|
||||
//require(startGas >= _gasLimit); // TODO: Tune this
|
||||
require(_nonce == nonce);
|
||||
require(_nonce == nonce, "Wrong nonce");
|
||||
|
||||
//verify if signatures are valid and came from correct actors;
|
||||
verifySignatures(
|
||||
|
@ -185,8 +141,8 @@ contract IdentityGasRelay is Identity {
|
|||
uint startGas = gasleft();
|
||||
|
||||
//verify transaction parameters
|
||||
require(startGas >= _gasLimit);
|
||||
require(_nonce == nonce);
|
||||
require(startGas >= _gasLimit, "Bad gas limit");
|
||||
require(_nonce == nonce, "Bad nonce");
|
||||
|
||||
//verify if signatures are valid and came from correct actors;
|
||||
verifySignatures(
|
||||
|
@ -226,14 +182,13 @@ contract IdentityGasRelay is Identity {
|
|||
* (`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 _baseToken token approved for `_to` and token being used for paying `msg.sender`
|
||||
* @param _to destination of call
|
||||
* @param _value call value (in `_baseToken`)
|
||||
* @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 _gasLimit minimal gasLimit required to execute this call
|
||||
* @param _gasToken token being used for paying `msg.sender`
|
||||
* @param _messageSignatures rsv concatenated ethereum signed message signatures required
|
||||
*/
|
||||
function approveAndCallGasRelayed(
|
||||
|
@ -244,7 +199,6 @@ contract IdentityGasRelay is Identity {
|
|||
uint _nonce,
|
||||
uint _gasPrice,
|
||||
uint _gasLimit,
|
||||
address _gasToken,
|
||||
bytes _messageSignatures
|
||||
)
|
||||
external
|
||||
|
@ -255,19 +209,20 @@ contract IdentityGasRelay is Identity {
|
|||
uint startGas = gasleft();
|
||||
|
||||
//verify transaction parameters
|
||||
// require(startGas >= _gasLimit); // TODO: tune this
|
||||
require(_nonce == nonce);
|
||||
// require(startGas >= _gasLimit, "Bad gas limit"); // TODO: tune this
|
||||
require(_nonce == nonce, "Bad nonce");
|
||||
|
||||
//verify if signatures are valid and came from correct actors;
|
||||
verifySignatures(
|
||||
ACTION_KEY,
|
||||
deployGasRelayHash(
|
||||
approveAndCallHash(
|
||||
_baseToken,
|
||||
_to,
|
||||
_value,
|
||||
keccak256(_data),
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
_gasLimit
|
||||
),
|
||||
_messageSignatures
|
||||
);
|
||||
|
@ -275,9 +230,9 @@ contract IdentityGasRelay is Identity {
|
|||
//increase nonce
|
||||
nonce++;
|
||||
|
||||
require(_baseToken != address(0)); //_baseToken should be something!
|
||||
require(_to != address(this)); //no management with approveAndCall
|
||||
require(_to != address(0)); //need valid destination
|
||||
require(_baseToken != address(0), "Bad token address"); //_baseToken should be something!
|
||||
require(_to != address(this), "Unauthorized call"); //no management with approveAndCall
|
||||
require(_to != address(0), "Bad destination"); //need valid destination
|
||||
ERC20Token(_baseToken).approve(_to, _value);
|
||||
success = _commitCall(_nonce, _to, 0, _data);
|
||||
|
||||
|
@ -285,11 +240,7 @@ contract IdentityGasRelay is Identity {
|
|||
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);
|
||||
}
|
||||
ERC20Token(_baseToken).transfer(msg.sender, _amount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +263,7 @@ contract IdentityGasRelay is Identity {
|
|||
// calculates signHash
|
||||
bytes32 signHash = getSignHash(_messageHash);
|
||||
uint _amountSignatures = _messageSignatures.length / 65;
|
||||
require(_amountSignatures == purposeThreshold[_requiredKey]);
|
||||
require(_amountSignatures == purposeThreshold[_requiredKey], "Too few signatures");
|
||||
bytes32 _lastKey = 0;
|
||||
for (uint256 i = 0; i < _amountSignatures; i++) {
|
||||
bytes32 _currentKey = recoverKey(
|
||||
|
@ -320,8 +271,8 @@ contract IdentityGasRelay is Identity {
|
|||
_messageSignatures,
|
||||
i
|
||||
);
|
||||
require(_currentKey > _lastKey); //assert keys are different
|
||||
require(keyHasPurpose(_currentKey, _requiredKey));
|
||||
require(_currentKey > _lastKey, "Bad signatures order"); //assert keys are different
|
||||
require(keyHasPurpose(_currentKey, _requiredKey), "Bad key");
|
||||
_lastKey = _currentKey;
|
||||
}
|
||||
return true;
|
||||
|
@ -353,19 +304,21 @@ contract IdentityGasRelay is Identity {
|
|||
returns (bytes32 _callGasRelayHash)
|
||||
{
|
||||
_callGasRelayHash = keccak256(
|
||||
address(this),
|
||||
MSG_CALL_PREFIX,
|
||||
_to,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
abi.encodePacked(
|
||||
address(this),
|
||||
MSG_CALL_PREFIX,
|
||||
_to,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @notice get callHash
|
||||
* @param _value call value (ether)
|
||||
* @param _dataHash call data hash
|
||||
|
@ -388,14 +341,54 @@ contract IdentityGasRelay is Identity {
|
|||
returns (bytes32 _callGasRelayHash)
|
||||
{
|
||||
_callGasRelayHash = keccak256(
|
||||
address(this),
|
||||
MSG_DEPLOY_PREFIX,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
abi.encodePacked(
|
||||
address(this),
|
||||
MSG_DEPLOY_PREFIX,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice get callHash
|
||||
* @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 _gasLimit minimal gasLimit required to execute this call
|
||||
* @param _gasToken token being used for paying `msg.sender`
|
||||
* @return callGasRelayHash the hash to be signed by wallet
|
||||
*/
|
||||
function approveAndCallHash(
|
||||
address _baseToken,
|
||||
address _to,
|
||||
uint256 _value,
|
||||
bytes32 _dataHash,
|
||||
uint _nonce,
|
||||
uint256 _gasPrice,
|
||||
uint256 _gasLimit
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bytes32 _callGasRelayHash)
|
||||
{
|
||||
_callGasRelayHash = keccak256(
|
||||
abi.encodePacked(
|
||||
address(this),
|
||||
MSG_APPROVEANDCALL_PREFIX,
|
||||
_baseToken,
|
||||
_to,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -426,16 +419,18 @@ contract IdentityGasRelay is Identity {
|
|||
returns (bytes32 _callGasRelayHash)
|
||||
{
|
||||
_callGasRelayHash = keccak256(
|
||||
address(this),
|
||||
MSG_APPROVEANDCALL_PREFIX,
|
||||
_baseToken,
|
||||
_to,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
abi.encodePacked(
|
||||
address(this),
|
||||
MSG_APPROVEANDCALL_PREFIX,
|
||||
_baseToken,
|
||||
_to,
|
||||
_value,
|
||||
_dataHash,
|
||||
_nonce,
|
||||
_gasPrice,
|
||||
_gasLimit,
|
||||
_gasToken
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -445,13 +440,13 @@ contract IdentityGasRelay is Identity {
|
|||
* @param _messageSignature message `_signHash` signature
|
||||
* @param _pos which signature to read
|
||||
*/
|
||||
function recoverKey (
|
||||
function recoverKey(
|
||||
bytes32 _signHash,
|
||||
bytes _messageSignature,
|
||||
uint256 _pos
|
||||
)
|
||||
pure
|
||||
public
|
||||
pure
|
||||
returns(bytes32)
|
||||
{
|
||||
uint8 v;
|
||||
|
@ -459,11 +454,13 @@ contract IdentityGasRelay is Identity {
|
|||
bytes32 s;
|
||||
(v,r,s) = signatureSplit(_messageSignature, _pos);
|
||||
return keccak256(
|
||||
ecrecover(
|
||||
_signHash,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
abi.encodePacked(
|
||||
ecrecover(
|
||||
_signHash,
|
||||
v,
|
||||
r,
|
||||
s
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -474,8 +471,8 @@ contract IdentityGasRelay is Identity {
|
|||
* @param _signatures concatenated vrs signatures
|
||||
*/
|
||||
function signatureSplit(bytes _signatures, uint256 _pos)
|
||||
pure
|
||||
internal
|
||||
pure
|
||||
returns (uint8 v, bytes32 r, bytes32 s)
|
||||
{
|
||||
uint pos = _pos + 1;
|
||||
|
@ -493,7 +490,7 @@ contract IdentityGasRelay is Identity {
|
|||
v := and(mload(add(_signatures, mul(65,pos))), 0xff)
|
||||
}
|
||||
|
||||
require(v == 27 || v == 28);
|
||||
require(v == 27 || v == 28, "Bad signature");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -513,7 +510,7 @@ contract IdentityGasRelay is Identity {
|
|||
createdContract := create(_value, add(_code, 0x20), mload(_code))
|
||||
failed := iszero(extcodesize(createdContract))
|
||||
}
|
||||
require(!failed);
|
||||
//require(!failed); removed as startGas needs to be lower then inner gasLimit
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue