Merge pull request #5 from status-im/maintance

Maintance of contract
This commit is contained in:
Richard Ramos 2018-11-19 14:52:20 -04:00 committed by GitHub
commit c037c16ad4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 127 additions and 157 deletions

View File

@ -23,7 +23,7 @@ contract IdentityFactory is Factory {
bytes32[] memory initKeys = new bytes32[](2); bytes32[] memory initKeys = new bytes32[](2);
uint256[] memory initPurposes = new uint256[](2); uint256[] memory initPurposes = new uint256[](2);
uint256[] memory initTypes = new uint256[](2); uint256[] memory initTypes = new uint256[](2);
initKeys[0] = keccak256(msg.sender); initKeys[0] = keccak256(abi.encodePacked(msg.sender));
initKeys[1] = initKeys[0]; initKeys[1] = initKeys[0];
initPurposes[0] = 1; initPurposes[0] = 1;
initPurposes[1] = 2; initPurposes[1] = 2;

View File

@ -11,63 +11,18 @@ import "../token/ERC20Token.sol";
*/ */
contract IdentityGasRelay is Identity { contract IdentityGasRelay is Identity {
bytes4 public constant MSG_CALL_PREFIX = bytes4(keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)")); bytes4 public constant MSG_CALL_PREFIX = bytes4(
bytes4 public constant MSG_DEPLOY_PREFIX = bytes4(keccak256("deployGasRelay(uint256,bytes32,uint256,uint256,address)")); keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)")
bytes4 public constant MSG_APPROVEANDCALL_PREFIX = bytes4(keccak256("approveAndCallGasRelay(address,address,uint256,bytes32,uint256,uint256)")); );
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); 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( constructor(
bytes32[] _keys, bytes32[] _keys,
uint256[] _purposes, uint256[] _purposes,
@ -97,7 +52,7 @@ contract IdentityGasRelay is Identity {
* @param _data call data * @param _data call data
* @param _nonce current identity nonce * @param _nonce current identity nonce
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used * @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 _gasMinimal minimal startGas required to execute this call
* @param _gasToken token being used for paying `msg.sender` * @param _gasToken token being used for paying `msg.sender`
* @param _messageSignatures rsv concatenated ethereum signed message signatures required * @param _messageSignatures rsv concatenated ethereum signed message signatures required
*/ */
@ -107,7 +62,7 @@ contract IdentityGasRelay is Identity {
bytes _data, bytes _data,
uint _nonce, uint _nonce,
uint _gasPrice, uint _gasPrice,
uint _gasLimit, uint _gasMinimal,
address _gasToken, address _gasToken,
bytes _messageSignatures bytes _messageSignatures
) )
@ -119,8 +74,8 @@ contract IdentityGasRelay is Identity {
uint startGas = gasleft(); uint startGas = gasleft();
//verify transaction parameters //verify transaction parameters
//require(startGas >= _gasLimit); // TODO: Tune this require(startGas >= _gasMinimal, "Bad gas left");
require(_nonce == nonce); require(_nonce == nonce, "Wrong nonce");
//verify if signatures are valid and came from correct actors; //verify if signatures are valid and came from correct actors;
verifySignatures( verifySignatures(
@ -131,7 +86,7 @@ contract IdentityGasRelay is Identity {
keccak256(_data), keccak256(_data),
_nonce, _nonce,
_gasPrice, _gasPrice,
_gasLimit, _gasMinimal,
_gasToken _gasToken
), ),
_messageSignatures _messageSignatures
@ -164,7 +119,7 @@ contract IdentityGasRelay is Identity {
* @param _data contract code data * @param _data contract code data
* @param _nonce current identity nonce * @param _nonce current identity nonce
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used * @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 _gasMinimal minimal startGas required to execute this call
* @param _gasToken token being used for paying `msg.sender` * @param _gasToken token being used for paying `msg.sender`
* @param _messageSignatures rsv concatenated ethereum signed message signatures required * @param _messageSignatures rsv concatenated ethereum signed message signatures required
*/ */
@ -173,7 +128,7 @@ contract IdentityGasRelay is Identity {
bytes _data, bytes _data,
uint _nonce, uint _nonce,
uint _gasPrice, uint _gasPrice,
uint _gasLimit, uint _gasMinimal,
address _gasToken, address _gasToken,
bytes _messageSignatures bytes _messageSignatures
) )
@ -185,8 +140,8 @@ contract IdentityGasRelay is Identity {
uint startGas = gasleft(); uint startGas = gasleft();
//verify transaction parameters //verify transaction parameters
require(startGas >= _gasLimit); require(startGas >= _gasMinimal, "Bad gas left");
require(_nonce == nonce); require(_nonce == nonce, "Bad nonce");
//verify if signatures are valid and came from correct actors; //verify if signatures are valid and came from correct actors;
verifySignatures( verifySignatures(
@ -196,7 +151,7 @@ contract IdentityGasRelay is Identity {
keccak256(_data), keccak256(_data),
_nonce, _nonce,
_gasPrice, _gasPrice,
_gasLimit, _gasMinimal,
_gasToken _gasToken
), ),
_messageSignatures _messageSignatures
@ -226,14 +181,13 @@ contract IdentityGasRelay is Identity {
* (`ERC20Token(baseToken).approve(_to, _value)` + `_to.call(_data)`). * (`ERC20Token(baseToken).approve(_to, _value)` + `_to.call(_data)`).
* in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken` * in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
* fixes race condition in double transaction for ERC20. * 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 _to destination of call
* @param _value call value (in `_baseToken`) * @param _value call value (in `_baseToken`)
* @param _data call data * @param _data call data
* @param _nonce current identity nonce * @param _nonce current identity nonce
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used * @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 _gasMinimal minimal startGas required to execute this call
* @param _gasToken token being used for paying `msg.sender`
* @param _messageSignatures rsv concatenated ethereum signed message signatures required * @param _messageSignatures rsv concatenated ethereum signed message signatures required
*/ */
function approveAndCallGasRelayed( function approveAndCallGasRelayed(
@ -243,8 +197,7 @@ contract IdentityGasRelay is Identity {
bytes _data, bytes _data,
uint _nonce, uint _nonce,
uint _gasPrice, uint _gasPrice,
uint _gasLimit, uint _gasMinimal,
address _gasToken,
bytes _messageSignatures bytes _messageSignatures
) )
external external
@ -255,19 +208,20 @@ contract IdentityGasRelay is Identity {
uint startGas = gasleft(); uint startGas = gasleft();
//verify transaction parameters //verify transaction parameters
// require(startGas >= _gasLimit); // TODO: tune this require(startGas >= _gasMinimal, "Bad gas left");
require(_nonce == nonce); require(_nonce == nonce, "Bad nonce");
//verify if signatures are valid and came from correct actors; //verify if signatures are valid and came from correct actors;
verifySignatures( verifySignatures(
ACTION_KEY, ACTION_KEY,
deployGasRelayHash( approveAndCallGasRelayHash(
_baseToken,
_to,
_value, _value,
keccak256(_data), keccak256(_data),
_nonce, _nonce,
_gasPrice, _gasPrice,
_gasLimit, _gasMinimal
_gasToken
), ),
_messageSignatures _messageSignatures
); );
@ -275,9 +229,9 @@ contract IdentityGasRelay is Identity {
//increase nonce //increase nonce
nonce++; nonce++;
require(_baseToken != address(0)); //_baseToken should be something! require(_baseToken != address(0), "Bad token address"); //_baseToken should be something!
require(_to != address(this)); //no management with approveAndCall require(_to != address(this), "Unauthorized call"); //no management with approveAndCall
require(_to != address(0)); //need valid destination require(_to != address(0), "Bad destination"); //need valid destination
ERC20Token(_baseToken).approve(_to, _value); ERC20Token(_baseToken).approve(_to, _value);
success = _commitCall(_nonce, _to, 0, _data); success = _commitCall(_nonce, _to, 0, _data);
@ -285,11 +239,7 @@ contract IdentityGasRelay is Identity {
if (_gasPrice > 0) { if (_gasPrice > 0) {
uint256 _amount = 21000 + (startGas - gasleft()); uint256 _amount = 21000 + (startGas - gasleft());
_amount = _amount * _gasPrice; _amount = _amount * _gasPrice;
if (_gasToken == address(0)) { ERC20Token(_baseToken).transfer(msg.sender, _amount);
address(msg.sender).transfer(_amount);
} else {
ERC20Token(_gasToken).transfer(msg.sender, _amount);
}
} }
} }
@ -312,7 +262,7 @@ contract IdentityGasRelay is Identity {
// calculates signHash // calculates signHash
bytes32 signHash = getSignHash(_messageHash); bytes32 signHash = getSignHash(_messageHash);
uint _amountSignatures = _messageSignatures.length / 65; uint _amountSignatures = _messageSignatures.length / 65;
require(_amountSignatures == purposeThreshold[_requiredKey]); require(_amountSignatures == purposeThreshold[_requiredKey], "Too few signatures");
bytes32 _lastKey = 0; bytes32 _lastKey = 0;
for (uint256 i = 0; i < _amountSignatures; i++) { for (uint256 i = 0; i < _amountSignatures; i++) {
bytes32 _currentKey = recoverKey( bytes32 _currentKey = recoverKey(
@ -320,8 +270,8 @@ contract IdentityGasRelay is Identity {
_messageSignatures, _messageSignatures,
i i
); );
require(_currentKey > _lastKey); //assert keys are different require(_currentKey > _lastKey, "Bad signatures order"); //assert keys are different
require(keyHasPurpose(_currentKey, _requiredKey)); require(keyHasPurpose(_currentKey, _requiredKey), "Bad key");
_lastKey = _currentKey; _lastKey = _currentKey;
} }
return true; return true;
@ -335,7 +285,7 @@ contract IdentityGasRelay is Identity {
* @param _dataHash call data hash * @param _dataHash call data hash
* @param _nonce current identity nonce * @param _nonce current identity nonce
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used * @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 _gasMinimal minimal startGas required to execute this call
* @param _gasToken token being used for paying `msg.sender` * @param _gasToken token being used for paying `msg.sender`
* @return callGasRelayHash the hash to be signed by wallet * @return callGasRelayHash the hash to be signed by wallet
*/ */
@ -345,7 +295,7 @@ contract IdentityGasRelay is Identity {
bytes32 _dataHash, bytes32 _dataHash,
uint _nonce, uint _nonce,
uint256 _gasPrice, uint256 _gasPrice,
uint256 _gasLimit, uint256 _gasMinimal,
address _gasToken address _gasToken
) )
public public
@ -353,25 +303,27 @@ contract IdentityGasRelay is Identity {
returns (bytes32 _callGasRelayHash) returns (bytes32 _callGasRelayHash)
{ {
_callGasRelayHash = keccak256( _callGasRelayHash = keccak256(
address(this), abi.encodePacked(
MSG_CALL_PREFIX, address(this),
_to, MSG_CALL_PREFIX,
_value, _to,
_dataHash, _value,
_nonce, _dataHash,
_gasPrice, _nonce,
_gasLimit, _gasPrice,
_gasToken _gasMinimal,
_gasToken
)
); );
} }
/** /**
* @notice get callHash * @notice get callHash
* @param _value call value (ether) * @param _value call value (ether)
* @param _dataHash call data hash * @param _dataHash call data hash
* @param _nonce current identity nonce * @param _nonce current identity nonce
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used * @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 _gasMinimal minimal startGas required to execute this call
* @param _gasToken token being used for paying `msg.sender` * @param _gasToken token being used for paying `msg.sender`
* @return callGasRelayHash the hash to be signed by wallet * @return callGasRelayHash the hash to be signed by wallet
*/ */
@ -380,7 +332,7 @@ contract IdentityGasRelay is Identity {
bytes32 _dataHash, bytes32 _dataHash,
uint256 _nonce, uint256 _nonce,
uint256 _gasPrice, uint256 _gasPrice,
uint256 _gasLimit, uint256 _gasMinimal,
address _gasToken address _gasToken
) )
public public
@ -388,26 +340,26 @@ contract IdentityGasRelay is Identity {
returns (bytes32 _callGasRelayHash) returns (bytes32 _callGasRelayHash)
{ {
_callGasRelayHash = keccak256( _callGasRelayHash = keccak256(
address(this), abi.encodePacked(
MSG_DEPLOY_PREFIX, address(this),
_value, MSG_DEPLOY_PREFIX,
_dataHash, _value,
_nonce, _dataHash,
_gasPrice, _nonce,
_gasLimit, _gasPrice,
_gasToken _gasMinimal,
_gasToken
)
); );
} }
/** /**
* @notice get callHash * @notice get callHash
* @param _to destination of call
* @param _value call value (ether) * @param _value call value (ether)
* @param _dataHash call data hash * @param _dataHash call data hash
* @param _nonce current identity nonce * @param _nonce current identity nonce
* @param _gasPrice price in SNT paid back to msg.sender for each gas unit used * @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 _gasMinimal minimal startGas required to execute this call
* @param _gasToken token being used for paying `msg.sender` * @param _gasToken token being used for paying `msg.sender`
* @return callGasRelayHash the hash to be signed by wallet * @return callGasRelayHash the hash to be signed by wallet
*/ */
@ -418,40 +370,41 @@ contract IdentityGasRelay is Identity {
bytes32 _dataHash, bytes32 _dataHash,
uint _nonce, uint _nonce,
uint256 _gasPrice, uint256 _gasPrice,
uint256 _gasLimit, uint256 _gasMinimal
address _gasToken
) )
public public
view view
returns (bytes32 _callGasRelayHash) returns (bytes32 _callGasRelayHash)
{ {
_callGasRelayHash = keccak256( _callGasRelayHash = keccak256(
address(this), abi.encodePacked(
MSG_APPROVEANDCALL_PREFIX, address(this),
_baseToken, MSG_APPROVEANDCALL_PREFIX,
_to, _baseToken,
_value, _to,
_dataHash, _value,
_nonce, _dataHash,
_gasPrice, _nonce,
_gasLimit, _gasPrice,
_gasToken _gasMinimal
)
); );
} }
/** /**
* @notice recovers key who signed the message * @notice recovers key who signed the message
* @param _signHash operation ethereum signed message hash * @param _signHash operation ethereum signed message hash
* @param _messageSignature message `_signHash` signature * @param _messageSignature message `_signHash` signature
* @param _pos which signature to read * @param _pos which signature to read
*/ */
function recoverKey ( function recoverKey(
bytes32 _signHash, bytes32 _signHash,
bytes _messageSignature, bytes _messageSignature,
uint256 _pos uint256 _pos
) )
pure
public public
pure
returns(bytes32) returns(bytes32)
{ {
uint8 v; uint8 v;
@ -459,11 +412,13 @@ contract IdentityGasRelay is Identity {
bytes32 s; bytes32 s;
(v,r,s) = signatureSplit(_messageSignature, _pos); (v,r,s) = signatureSplit(_messageSignature, _pos);
return keccak256( return keccak256(
ecrecover( abi.encodePacked(
_signHash, ecrecover(
v, _signHash,
r, v,
s r,
s
)
) )
); );
} }
@ -474,8 +429,8 @@ contract IdentityGasRelay is Identity {
* @param _signatures concatenated vrs signatures * @param _signatures concatenated vrs signatures
*/ */
function signatureSplit(bytes _signatures, uint256 _pos) function signatureSplit(bytes _signatures, uint256 _pos)
pure
internal internal
pure
returns (uint8 v, bytes32 r, bytes32 s) returns (uint8 v, bytes32 r, bytes32 s)
{ {
uint pos = _pos + 1; uint pos = _pos + 1;
@ -493,7 +448,7 @@ contract IdentityGasRelay is Identity {
v := and(mload(add(_signatures, mul(65,pos))), 0xff) v := and(mload(add(_signatures, mul(65,pos))), 0xff)
} }
require(v == 27 || v == 28); require(v == 27 || v == 28, "Bad signature");
} }
/** /**
@ -508,12 +463,10 @@ contract IdentityGasRelay is Identity {
internal internal
returns (address createdContract) returns (address createdContract)
{ {
bool failed;
assembly { assembly {
createdContract := create(_value, add(_code, 0x20), mload(_code)) 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 _gasMinimal
} }
} }

View File

@ -14,8 +14,12 @@ import "../token/MiniMeToken.sol";
contract SNTController is TokenController, Owned, MessageSigned { contract SNTController is TokenController, Owned, MessageSigned {
bytes4 public constant TRANSFER_PREFIX = bytes4(keccak256("transferSNT(address,uint256,uint256,uint256)")); bytes4 public constant TRANSFER_PREFIX = bytes4(
bytes4 public constant EXECUTE_PREFIX = bytes4(keccak256("executeGasRelayed(address,bytes,uint256,uint256,uint256)")); keccak256("transferSNT(address,uint256,uint256,uint256)")
);
bytes4 public constant EXECUTE_PREFIX = bytes4(
keccak256("executeGasRelayed(address,bytes,uint256,uint256,uint256)")
);
MiniMeToken public snt; MiniMeToken public snt;
mapping (address => uint256) public signNonce; mapping (address => uint256) public signNonce;
@ -31,7 +35,7 @@ contract SNTController is TokenController, Owned, MessageSigned {
* @param _owner Authority address * @param _owner Authority address
* @param _snt SNT token * @param _snt SNT token
*/ */
function SNTController(address _owner, address _snt) public { constructor(address _owner, address _snt) public {
owner = _owner; owner = _owner;
snt = MiniMeToken(_snt); snt = MiniMeToken(_snt);
} }
@ -64,10 +68,17 @@ contract SNTController is TokenController, Owned, MessageSigned {
); );
address msgSigner = recoverAddress(msgSigned, _signature); address msgSigner = recoverAddress(msgSigned, _signature);
require(signNonce[msgSigner] == _nonce); require(signNonce[msgSigner] == _nonce, "Bad nonce");
signNonce[msgSigner]++; signNonce[msgSigner]++;
if (snt.transferFrom(msgSigner, _to, _amount)) { if (snt.transferFrom(msgSigner, _to, _amount)) {
require(snt.transferFrom(msgSigner, msg.sender, (21000 + startGas-gasleft()) * _gasPrice)); require(
snt.transferFrom(
msgSigner,
msg.sender,
(21000 + startGas - gasleft()) * _gasPrice
),
"Gas transfer fail"
);
} }
} }
@ -91,7 +102,8 @@ contract SNTController is TokenController, Owned, MessageSigned {
external external
{ {
uint256 startGas = gasleft(); uint256 startGas = gasleft();
require(startGas >= _gasMinimal); require(startGas >= _gasMinimal, "Bad gas left");
require(allowPublicExecution[_allowedContract], "Unallowed call");
bytes32 msgSigned = getSignHash( bytes32 msgSigned = getSignHash(
getExecuteGasRelayedHash( getExecuteGasRelayedHash(
_allowedContract, _allowedContract,
@ -103,7 +115,7 @@ contract SNTController is TokenController, Owned, MessageSigned {
); );
address msgSigner = recoverAddress(msgSigned, _signature); address msgSigner = recoverAddress(msgSigned, _signature);
require(signNonce[msgSigner] == _nonce); require(signNonce[msgSigner] == _nonce, "Bad nonce");
signNonce[msgSigner]++; signNonce[msgSigner]++;
bool success = _allowedContract.call(_data); bool success = _allowedContract.call(_data);
emit GasRelayedExecution(msgSigner, msgSigned, success); emit GasRelayedExecution(msgSigner, msgSigned, success);
@ -112,7 +124,8 @@ contract SNTController is TokenController, Owned, MessageSigned {
msgSigner, msgSigner,
msg.sender, msg.sender,
(21000 + startGas-gasleft()) * _gasPrice (21000 + startGas-gasleft()) * _gasPrice
) ),
"Gas transfer fail"
); );
} }
@ -146,7 +159,7 @@ contract SNTController is TokenController, Owned, MessageSigned {
snt.claimTokens(_token); snt.claimTokens(_token);
} }
if (_token == 0x0) { if (_token == 0x0) {
address(owner).transfer(this.balance); address(owner).transfer(address(this).balance);
return; return;
} }
@ -194,13 +207,15 @@ contract SNTController is TokenController, Owned, MessageSigned {
returns (bytes32 execHash) returns (bytes32 execHash)
{ {
execHash = keccak256( execHash = keccak256(
address(this), abi.encodePacked(
EXECUTE_PREFIX, address(this),
_allowedContract, EXECUTE_PREFIX,
keccak256(_data), _allowedContract,
_nonce, keccak256(_data),
_gasPrice, _nonce,
_gasMinimal _gasPrice,
_gasMinimal
)
); );
} }
@ -222,12 +237,14 @@ contract SNTController is TokenController, Owned, MessageSigned {
returns (bytes32 txHash) returns (bytes32 txHash)
{ {
txHash = keccak256( txHash = keccak256(
address(this), abi.encodePacked(
TRANSFER_PREFIX, address(this),
_to, TRANSFER_PREFIX,
_amount, _to,
_nonce, _amount,
_gasPrice _nonce,
_gasPrice
)
); );
} }