From ffb4fa6ef55105449d93d1169553e0636c434c7c Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Tue, 8 May 2018 20:12:32 -0300 Subject: [PATCH] replace repeated logic in a modifier, change const names, change event --- contracts/identity/IdentityGasRelay.sol | 233 +++++++++++------------- 1 file changed, 102 insertions(+), 131 deletions(-) diff --git a/contracts/identity/IdentityGasRelay.sol b/contracts/identity/IdentityGasRelay.sol index afccca5..19b9360 100644 --- a/contracts/identity/IdentityGasRelay.sol +++ b/contracts/identity/IdentityGasRelay.sol @@ -11,13 +11,68 @@ import "../token/ERC20Token.sol"; */ contract IdentityGasRelay is Identity, MessageSigned { - bytes4 public constant CALL_PREFIX = bytes4(keccak256("callGasRelay(address,uint256,bytes32,uint256,uint256,address)")); - bytes4 public constant DEPLOY_PREFIX = bytes4(keccak256("deployGasRelay(uint256,bytes32,uint256,uint256,address)")); - bytes4 public constant 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 signHash, bool success); + event ExecutedGasRelayed(bytes32 messageHash); event ContractDeployed(address deployedAddress); + /** + * @param _messageHash that is signed + * @param _required 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 gasRelayed ( + 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 + _; + + //signal execution to event listeners + emit ExecutedGasRelayed( + _messageHash + ); + + //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 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 @@ -41,13 +96,7 @@ contract IdentityGasRelay is Identity, MessageSigned { bytes _messageSignatures ) external - { - uint startGas = gasleft(); - //verify transaction parameters - require(startGas >= _gasLimit); - require(_nonce == nonce); - // calculates signHash - bytes32 signHash = getSignHash( + gasRelayed( callGasRelayHash( _to, _value, @@ -56,34 +105,17 @@ contract IdentityGasRelay is Identity, MessageSigned { _gasPrice, _gasLimit, _gasToken - ) - ); - - //verify if signatures are valid and came from correct actors; - verifySignatures( + ), _to == address(this) ? MANAGEMENT_KEY : ACTION_KEY, - signHash, + _nonce, + _gasPrice, + _gasLimit, + _gasToken, _messageSignatures - ); - - //executes transaction - nonce++; - bool success = _to.call.value(_value)(_data); - emit ExecutedGasRelayed( - signHash, - success - ); - - //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); - } - } + ) + returns (bool success) + { + success = _to.call.value(_value)(_data); } @@ -108,14 +140,7 @@ contract IdentityGasRelay is Identity, MessageSigned { bytes _messageSignatures ) external - returns(address deployedAddress) - { - uint startGas = gasleft(); - //verify transaction parameters - require(startGas >= _gasLimit); - require(_nonce == nonce); - // calculates signHash - bytes32 signHash = getSignHash( + gasRelayed( deployGasRelayHash( _value, keccak256(_data), @@ -123,32 +148,18 @@ contract IdentityGasRelay is Identity, MessageSigned { _gasPrice, _gasLimit, _gasToken - ) - ); - - //verify if signatures are valid and came from correct actors; - verifySignatures( + ), ACTION_KEY, - signHash, + _nonce, + _gasPrice, + _gasLimit, + _gasToken, _messageSignatures - ); - - //executes transaction - nonce++; + ) + returns(address deployedAddress) + { deployedAddress = doCreate(_value, _data); - emit ContractDeployed(deployedAddress); - - //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); - } - } - + emit ContractDeployed(deployedAddress); } @@ -179,16 +190,7 @@ contract IdentityGasRelay is Identity, MessageSigned { bytes _messageSignatures ) external - { - uint startGas = gasleft(); - //verify transaction parameters - require(startGas >= _gasLimit); - require(_nonce == nonce); - require(_baseToken != address(0)); //_baseToken should be something! - require(_to != address(this)); //no management with approveAndCall - - // calculates signHash - bytes32 signHash = getSignHash( + gasRelayed( approveAndCallGasRelayHash( _baseToken, _to, @@ -198,59 +200,47 @@ contract IdentityGasRelay is Identity, MessageSigned { _gasPrice, _gasLimit, _gasToken - ) - ); - - //verify if signatures are valid and came from correct actors; - verifySignatures( - ACTION_KEY, //no management with approveAndCall - signHash, + ), + ACTION_KEY, + _nonce, + _gasPrice, + _gasLimit, + _gasToken, _messageSignatures - ); + ) + returns(bool success) + { + require(_baseToken != address(0)); //_baseToken should be something! + require(_to != address(this)); //no management with approveAndCall - 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); - } - } - + ERC20Token(_baseToken).approve(_to, _value); + success = _to.call(_data); } /** * @notice reverts if signatures are not valid for the signed hash and required key type. * @param _requiredKey key required to call, if _to from payload is the identity itself, is `MANAGEMENT_KEY`, else `ACTION_KEY` - * @param _signHash ethereum signable callGasRelayHash message provided for the payload - * @param _messageSignatures ethereum signed `_signHash` messages + * @param _messageHash message hash provided for the payload + * @param _messageSignatures ethereum signed `getSignHash(_messageHash)` message * @return true case valid */ function verifySignatures( uint256 _requiredKey, - bytes32 _signHash, + bytes32 _messageHash, bytes _messageSignatures ) public view returns(bool) { + // calculates signHash + bytes32 signHash = getSignHash(_messageHash); uint _amountSignatures = _messageSignatures.length / 65; require(_amountSignatures == purposeThreshold[_requiredKey]); bytes32 _lastKey = 0; for (uint256 i = 0; i < _amountSignatures; i++) { bytes32 _currentKey = recoverKey( - _signHash, + signHash, _messageSignatures, i ); @@ -288,7 +278,7 @@ contract IdentityGasRelay is Identity, MessageSigned { { _callGasRelayHash = keccak256( address(this), - CALL_PREFIX, + MSG_CALL_PREFIX, _to, _value, _dataHash, @@ -323,7 +313,7 @@ contract IdentityGasRelay is Identity, MessageSigned { { _callGasRelayHash = keccak256( address(this), - DEPLOY_PREFIX, + MSG_DEPLOY_PREFIX, _value, _dataHash, _nonce, @@ -361,7 +351,7 @@ contract IdentityGasRelay is Identity, MessageSigned { { _callGasRelayHash = keccak256( address(this), - APPROVEANDCALL_PREFIX, + MSG_APPROVEANDCALL_PREFIX, _baseToken, _to, _value, @@ -429,25 +419,6 @@ contract IdentityGasRelay is Identity, MessageSigned { 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) - ); - - } /** * @notice creates new contract based on input `_code` and transfer `_value` ETH to this instance