commit
c037c16ad4
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue