diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..7cc88f065 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sol linguist-language=Solidity \ No newline at end of file diff --git a/.gitignore b/.gitignore index 30bc16279..07e6e472c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/node_modules \ No newline at end of file +/node_modules diff --git a/README.md b/README.md index 19554bbdb..31f76c1b6 100644 --- a/README.md +++ b/README.md @@ -36,42 +36,22 @@ Clone the project and install all dependencies: git clone git@github.com:oceanprotocol/contracts.git cd contracts/ -# install openzeppelin cli and contracts-ethereum package -npm install @openzeppelin/cli +# TODO -npm install @openzeppelin/contracts-ethereum-package +TODO -# install openzeppelin test environment -npm install --save-dev mocha chai - -npm install --save-dev @openzeppelin/test-helpers - -npm install --save-dev @openzeppelin/test-environment - -``` - -Initialize openzeppelin project: - -```bash -oz innit -``` - -Compile the solidity contracts: - -```bash -oz compile ``` -In a new terminal, launch an Ethereum RPC client, e.g. [ganache-cli](https://github.com/trufflesuite/ganache-cli): +TODO: ```bash -ganache-cli +TODO ``` -Switch back to your other terminal and deploy the contracts: +TODO: ```bash -oz publish +TODO ``` diff --git a/contracts/DataToken.sol b/contracts/DataToken.sol index a39823482..ad4f18f89 100644 --- a/contracts/DataToken.sol +++ b/contracts/DataToken.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.5.3; +pragma solidity ^0.5.0; import './Fees.sol'; import './TokenFactory.sol'; @@ -21,29 +21,40 @@ contract DataToken is Initializable, ERC20, Fees, Ownable { string public metadata; TokenFactory public factory; - event Initialized(address indexed thisAddress); + bool public initialized = false; + + event Initialized( + address indexed thisAddress + ); + + event TokenMinted( + address indexed to, + uint256 amount, + uint256 fee, + uint256 cashBack + ); /** * @notice initializer - * @param _metadata Data token metadata - * @param _publisher publisher(contract owner) address */ function initialize( - string memory _metadata, + string memory _metadata, address _publisher ) public initializer { + Ownable.initialize(_publisher); factory = TokenFactory(msg.sender); metadata = _metadata; - uint256 tokenNumber = factory.getTokenCount(); + uint256 tokenNumber = factory.tokenCount(); - symbol = string(abi.encodePacked('ODT-', tokenNumber.add(1))); - name = string(abi.encodePacked('OceanDataToken-', tokenNumber.add(1))); + symbol = string(abi.encodePacked('ODT-', tokenNumber.add(1))); + name = string(abi.encodePacked('OceanDataToken-', tokenNumber.add(1))); + initialized = true; emit Initialized(address(this)); } @@ -61,14 +72,32 @@ contract DataToken is Initializable, ERC20, Fees, Ownable { payable onlyOwner { - uint256 startGas = gasleft(); + //additional check so it does not revert with SafeMath: subtraction overflow + require(msg.value > 0, + "fee amount is not enough"); + uint256 startGas = gasleft(); + address payable beneficiary = factory.beneficiary(); + address payable sender = msg.sender; + + //mint tokens _mint(address(this), _amount); + + uint256 fee = _getFee(startGas); + uint256 cashback = _getCashback(fee, msg.value); + + // discuss: change to "==" + require(msg.value >= fee, + "fee amount is not enough"); - require(_isPayed(startGas, msg.value), - "fee is not payed"); - //TODO: add transfer fee to beneficiary + //transfer fee to beneficiary + beneficiary.transfer(fee); + // return cashback + sender.transfer(cashback); + _transfer(address(this), _to, _amount); + + emit TokenMinted(_to, _amount, fee, cashback); } } \ No newline at end of file diff --git a/contracts/Fees.sol b/contracts/Fees.sol index 320c4370b..00b39f1d9 100644 --- a/contracts/Fees.sol +++ b/contracts/Fees.sol @@ -6,16 +6,25 @@ contract Fees { using SafeMath for uint256; - function _isPayed( - uint256 _startGas, - uint256 _msgValue + function _getFee( + uint256 _startGas ) public view - returns(bool) + returns(uint256) { uint256 usedGas = _startGas.sub(gasleft()); - return usedGas.mul(tx.gasprice) >= _msgValue; //TODO: should be changed to '==' + return usedGas.mul(tx.gasprice); } + function _getCashback( + uint256 _fee, + uint256 _payed + ) + public + pure + returns(uint256) + { + return _payed.sub(_fee); + } } \ No newline at end of file diff --git a/contracts/TokenFactory.sol b/contracts/TokenFactory.sol index 083ed0fd3..916881746 100644 --- a/contracts/TokenFactory.sol +++ b/contracts/TokenFactory.sol @@ -1,10 +1,10 @@ -pragma solidity ^0.5.3; +pragma solidity ^0.5.0; import './Fees.sol'; import './DataToken.sol'; +import '@openzeppelin/upgrades/contracts/upgradeability/ProxyFactory.sol'; import '@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol'; import '@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol'; -import '@openzeppelin/upgrades/contracts/upgradeability/ProxyFactory.sol'; /** * @title TokenFactory @@ -14,9 +14,9 @@ contract TokenFactory is ProxyFactory, Ownable, Fees { using SafeMath for uint256; - address payable beneficiary; - address public template; - uint256 public tokenCount; + address payable public beneficiary; + address public template; + uint256 public tokenCount; mapping (uint256 => address) idToToken; mapping (address => uint256) tokenToId; @@ -48,21 +48,33 @@ contract TokenFactory is ProxyFactory, Ownable, Fees { ) public payable + returns(address) { - uint256 startGas = gasleft(); - - bytes memory _payload = abi.encodeWithSignature("initialize(string, address)", _metadata, msg.sender); - address token = deployMinimal(template, _payload); - - tokenCount = tokenCount.add(1); - idToToken[tokenCount] = token; - tokenToId[token] = tokenCount; - - require(_isPayed(startGas, msg.value), - "fee is not payed"); - //TODO: add transfer fee to beneficiary + uint256 startGas = gasleft(); + + bytes memory _payload = abi.encodeWithSignature("initialize(string,address)", _metadata, msg.sender); + address token = deployMinimal(template, _payload); + address payable sender = msg.sender; + + tokenCount = tokenCount.add(1); + idToToken[tokenCount] = token; + tokenToId[token] = tokenCount; + + uint256 fee = _getFee(startGas); + + // discuss: change to "==" + require(msg.value >= fee, + "fee amount is not enough"); + + //transfer fee to beneficiary + beneficiary.transfer(fee); + // return cashback + sender.transfer(_getCashback(fee, msg.value)); + + return token; } + /** * @notice Get Data Token contract address * @param tokenId token id @@ -94,20 +106,8 @@ contract TokenFactory is ProxyFactory, Ownable, Fees { } /** - * @notice Get total number of tokens deployed - * @return number of tokens deployed - */ - function getTokenCount() - public - view - returns(uint256) - { - return tokenCount; - } - - /** - * @notice Change beneficiarry address(only contract owner can do that) - * @param newBeneficiary new beneficiarry address + * @notice Change beneficiary address(only contract owner can do that) + * @param newBeneficiary new beneficiary address */ function changeBeneficiary( address payable newBeneficiary diff --git a/networks.js b/networks.js deleted file mode 100644 index 33894add9..000000000 --- a/networks.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - networks: { - development: { - protocol: 'http', - host: 'localhost', - port: 8545, - gas: 5000000, - gasPrice: 5e9, - networkId: '*', - }, - }, -}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 7286320bc..000000000 --- a/package-lock.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dev": true, - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==", - "dev": true - } - } - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - } - } -}