From d12683b9b4b5226220c0527d7008c332cf19b6b3 Mon Sep 17 00:00:00 2001 From: Ricardo Guilherme Schmidt <3esmit@gmail.com> Date: Wed, 24 Jan 2018 02:51:49 +0000 Subject: [PATCH] presigned token --- .gitignore | 3 + contracts/status/SNTPreSigned.sol | 26 +++ contracts/token/MiniMeTokenPreSigned.sol | 160 ++++++++++++++++++ .../token/MiniMeTokenPreSignedFactory.sol | 45 +++++ 4 files changed, 234 insertions(+) create mode 100644 contracts/status/SNTPreSigned.sol create mode 100644 contracts/token/MiniMeTokenPreSigned.sol create mode 100644 contracts/token/MiniMeTokenPreSignedFactory.sol diff --git a/.gitignore b/.gitignore index aa59eb2..e4f9685 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ coverage.json # node node_modules/ npm-debug.log + +# ide +.vs/ \ No newline at end of file diff --git a/contracts/status/SNTPreSigned.sol b/contracts/status/SNTPreSigned.sol new file mode 100644 index 0000000..e11257c --- /dev/null +++ b/contracts/status/SNTPreSigned.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.11; + +import "../token/MiniMeTokenPreSigned.sol"; +import "../token/MiniMeTokenPreSignedFactory.sol"; + +/* + Copyright 2017, Jarrad Hope (Status Research & Development GmbH) +*/ + +contract SNTPreSigned is MiniMeTokenPreSigned { + // @dev SNT constructor just parametrizes the MiniMeIrrevocableVestedToken constructor + function SNTPreSigned(address _oldToken) + MiniMeToken( + new MiniMeTokenPreSignedFactory(), + _oldToken, // parent token + block.number, // snapshot block + "Status Network Token", // Token name + 18, // Decimals + "SNT", // Symbol + true // Enable transfers + ) + public + { + + } +} \ No newline at end of file diff --git a/contracts/token/MiniMeTokenPreSigned.sol b/contracts/token/MiniMeTokenPreSigned.sol new file mode 100644 index 0000000..cd84592 --- /dev/null +++ b/contracts/token/MiniMeTokenPreSigned.sol @@ -0,0 +1,160 @@ +pragma solidity ^0.4.18; + +import "./MiniMeToken.sol"; + +/** + * @title StatusConstitution + * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH) + * @dev MiniMeToken that supports pre-signed methods transfer(address,uint256) and approveAndCall(address,uint256,bytes) + */ +contract MiniMeTokenPreSigned is MiniMeToken { + + mapping (address => uint256) public nonce; + + /** + * @notice Include a presigned `transfer(address,uint256)` + * @param _sigV Signature V + * @param _sigR Signature R + * @param _sigS Signature S + * @param _to The address of the recipient + * @param _value The amount of tokens to be transferred + * @param _gasPrice How much tokens willing to pay per gas + * @param _nonce Presigned transaction number. + */ + function transferPreSigned( + uint8 _sigV, + bytes32 _sigR, + bytes32 _sigS, + address _to, + uint256 _value, + uint256 _gasPrice, + uint256 _nonce + ) + public + { + uint256 _gas = msg.gas; + //"a9059cbb": "transfer(address,uint256)", + bytes32 txHash = keccak256(byte(0x19), byte(0), address(this), bytes4(0xa9059cbb), _to, _value, _gasPrice, _nonce); + address recovered = ecrecover(txHash, _sigV, _sigR, _sigS); + require(recovered > 0x0); + require(nonce[recovered] == _nonce); + nonce[recovered]++; + require(doTransfer(recovered, _to, _value)); + _gas = 21000 + (_gas - msg.gas); + if (_gasPrice > 0) { + require(doTransfer(recovered, msg.sender, _gasPrice * _gas)); + } + } + + /** + * @notice Include a presigned `approveAndCall(address,uint256,bytes)` + * @param _sigV Signature V + * @param _sigR Signature R + * @param _sigS Signature S + * @param _spender The address of the recipient + * @param _amount The amount of tokens to be transferred + * @param _extraData option data to send to contract + * @param _gasPrice How much tokens willing to pay per gas + * @param _nonce Presigned transaction number. + */ + function approveAndCallPreSigned( + uint8 _sigV, + bytes32 _sigR, + bytes32 _sigS, + address _spender, + uint256 _amount, + bytes _extraData, + uint256 _gasPrice, + uint256 _nonce + ) + public + { + uint256 _gas = msg.gas; + require(transfersEnabled); + //"cae9ca51": "approveAndCall(address,uint256,bytes)" + bytes32 txHash = keccak256(byte(0x19), byte(0), address(this), bytes4(0xcae9ca51), _spender, _amount, _extraData, _gasPrice, _nonce); + address recovered = ecrecover(txHash, _sigV, _sigR, _sigS); + require(recovered > 0x0); + require(nonce[recovered] == _nonce); + nonce[recovered]++; + + require((_amount == 0) || (allowed[recovered][_spender] == 0)); + if (isContract(controller)) { + require(TokenController(controller).onApprove(recovered, _spender, _amount)); + } + allowed[recovered][_spender] = _amount; + Approval(recovered, _spender, _amount); + ApproveAndCallFallBack(_spender).receiveApproval( + recovered, + _amount, + this, + _extraData + ); + _gas = 21000 + (_gas - msg.gas); + if (_gasPrice > 0) { + require(doTransfer(recovered, msg.sender, _gasPrice*_gas)); + } + + } + + /** + * @notice Include batches of presigned `approveAndCall(address,uint256,bytes)` + * @param _sigV Signature V + * @param _sigR Signature R + * @param _sigS Signature S + * @param _spender The address of the recipient + * @param _amount The amount of tokens to be transferred + * @param _extraData option data to send to contract + * @param _gasPrice How much tokens willing to pay per gas + * @param _nonce Presigned transaction number. + */ + function approveAndCallPreSigned( + uint8[] _sigV, + bytes32[] _sigR, + bytes32[] _sigS, + address[] _spender, + uint256[] _amount, + bytes[] _extraData, + uint256[] _gasPrice, + uint256[] _nonce + ) + public + { + uint len = _sigR.length; + require(len == _sigS.length && len == _sigV.length); + for (uint i = 0; i < len; i++) { + approveAndCallPreSigned(_sigV[i], _sigR[i], _sigS[i], _spender[i], _amount[i], _extraData[i], _gasPrice[i], _nonce[i]); + } + } + + + + /** + * @notice Include batches of presigned `transfer(address,uint256)` + * @param _sigV Signature V + * @param _sigR Signature R + * @param _sigS Signature S + * @param _to The address of the recipient + * @param _value The amount of tokens to be transferred + * @param _gasPrice How much tokens willing to pay per gas + * @param _nonce Presigned transaction number. + */ + function transferPreSigned( + uint8[] _sigV, + bytes32[] _sigR, + bytes32[] _sigS, + address[] _to, + uint256[] _value, + uint256[] _gasPrice, + uint256[] _nonce + ) + public + { + uint len = _sigR.length; + require(len == _sigS.length && len == _sigV.length); + for (uint i = 0; i < len; i++) { + transferPreSigned(_sigV[i], _sigR[i], _sigS[i], _to[i], _value[i], _gasPrice[i], _nonce[i]); + } + } + +} \ No newline at end of file diff --git a/contracts/token/MiniMeTokenPreSignedFactory.sol b/contracts/token/MiniMeTokenPreSignedFactory.sol new file mode 100644 index 0000000..9fa2f89 --- /dev/null +++ b/contracts/token/MiniMeTokenPreSignedFactory.sol @@ -0,0 +1,45 @@ +pragma solidity ^0.4.11; + +import "./MiniMeTokenPreSigned.sol"; + +//////////////// +// MiniMeTokenFactory +//////////////// + +/// @dev This contract is used to generate clone contracts from a contract. +/// In solidity this is the way to create a contract from a contract of the +/// same class +contract MiniMeTokenPreSignedFactory { + + /// @notice Update the DApp by creating a new token with new functionalities + /// the msg.sender becomes the controller of this clone token + /// @param _parentToken Address of the token being cloned + /// @param _snapshotBlock Block of the parent token that will + /// determine the initial distribution of the clone token + /// @param _tokenName Name of the new token + /// @param _decimalUnits Number of decimals of the new token + /// @param _tokenSymbol Token Symbol for the new token + /// @param _transfersEnabled If true, tokens will be able to be transferred + /// @return The address of the new token contract + function createCloneToken( + address _parentToken, + uint _snapshotBlock, + string _tokenName, + uint8 _decimalUnits, + string _tokenSymbol, + bool _transfersEnabled + ) returns (MiniMeTokenPreSigned) { + MiniMeTokenPreSigned newToken = new MiniMeTokenPreSigned( + this, + _parentToken, + _snapshotBlock, + _tokenName, + _decimalUnits, + _tokenSymbol, + _transfersEnabled + ); + + newToken.changeController(msg.sender); + return newToken; + } +} \ No newline at end of file