From 800ad2270e014418206a7ecbdaecb4c8b08cd1d3 Mon Sep 17 00:00:00 2001 From: Andy Tudhope Date: Fri, 12 Apr 2019 11:40:24 +0200 Subject: [PATCH] storing ipfs hash in bytes32 hash and changed receiveApproval (#23) --- contracts/DAppStore.sol | 44 ++++++++++++++++++++++++++++++----------- package.json | 2 ++ test/dappstore_spec.js | 12 +++++++---- utils/testUtils.js | 16 ++++++++++++++- 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/contracts/DAppStore.sol b/contracts/DAppStore.sol index e9616f5..d8b45cf 100644 --- a/contracts/DAppStore.sol +++ b/contracts/DAppStore.sol @@ -31,7 +31,7 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { struct Data { address developer; bytes32 id; - bytes metadata; + bytes32 metadata; uint balance; uint rate; uint available; @@ -68,9 +68,14 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { * @dev Anyone can create a DApp (i.e an arb piece of data this contract happens to care about). * @param _id bytes32 unique identifier. * @param _amount of tokens to stake on initial ranking. + * @param _metadata metadata hex string */ - function createDApp(bytes32 _id, uint _amount) external { - _createDApp(msg.sender, _id, _amount); + function createDApp(bytes32 _id, uint _amount, bytes32 _metadata) external { + _createDApp( + msg.sender, + _id, + _amount, + _metadata); } /** @@ -139,9 +144,9 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { /** * dev Set the content for the dapp * @param _id bytes32 unique identifier. - * @param _metadata IPFS hash of the metadata + * @param _metadata metadata info */ - function setMetadata(bytes32 _id, bytes calldata _metadata) external { + function setMetadata(bytes32 _id, bytes32 _metadata) external { uint dappIdx = id2index[_id]; Data storage d = dapps[dappIdx]; require(d.developer == msg.sender, "Only the developer can update the metadata"); @@ -166,18 +171,22 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { { require(_token == address(SNT), "Wrong token"); require(_token == address(msg.sender), "Wrong account"); - require(_data.length <= 132, "Incorrect data"); + require(_data.length <= 196, "Incorrect data"); bytes4 sig; bytes32 id; uint256 amount; + bytes32 metadata; - (sig, id, amount) = abiDecodeRegister(_data); - + (sig, id, amount, metadata) = abiDecodeRegister(_data); require(_amount == amount, "Wrong amount"); - if (sig == bytes4(0x1a214f43)) { - _createDApp(_from, id, amount); + if (sig == bytes4(0x7e38d973)) { + _createDApp( + _from, + id, + amount, + metadata); } else if (sig == bytes4(0xac769090)) { _downvote(_from, id, amount); } else if (sig == bytes4(0x2b3df690)) { @@ -246,7 +255,14 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { return (balanceDownBy, votesRequired, cost); } - function _createDApp(address _from, bytes32 _id, uint _amount) internal { + function _createDApp( + address _from, + bytes32 _id, + uint _amount, + bytes32 _metadata + ) + internal + { require(!existingIDs[_id], "You must submit a unique ID"); require(_amount > 0, "You must spend some SNT to submit a ranking in order to avoid spam"); @@ -259,6 +275,7 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { Data storage d = dapps[dappIdx]; d.developer = _from; d.id = _id; + d.metadata = _metadata; uint precision; uint result; @@ -351,16 +368,19 @@ contract DAppStore is ApproveAndCallFallBack, BancorFormula { bytes memory _data ) private + pure returns( bytes4 sig, bytes32 id, - uint256 amount + uint256 amount, + bytes32 metadata ) { assembly { sig := mload(add(_data, add(0x20, 0))) id := mload(add(_data, 36)) amount := mload(add(_data, 68)) + metadata := mload(add(_data, 100)) } } diff --git a/package.json b/package.json index 15bdea2..62e255f 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "private": true, "dependencies": { "@trailofbits/embark-contract-info": "^1.0.0", + "bignumber.js": "^8.1.1", + "bs58": "^4.0.1", "connected-react-router": "^6.3.2", "debounce": "^1.2.0", "decimal.js": "^10.0.2", diff --git a/test/dappstore_spec.js b/test/dappstore_spec.js index bd72e8d..07a33f6 100644 --- a/test/dappstore_spec.js +++ b/test/dappstore_spec.js @@ -54,9 +54,10 @@ contract("DAppStore", function () { it("should create a new DApp and initialise it correctly", async function () { let id = "0x7465737400000000000000000000000000000000000000000000000000000000"; let amount = 10000; + let metadata = "QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue"; await SNT.methods.generateTokens(accounts[0], amount).send(); - const encodedCall = DAppStore.methods.createDApp(id,amount).encodeABI(); + const encodedCall = DAppStore.methods.createDApp(id,amount,TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI(); await SNT.methods.approveAndCall(DAppStore.options.address, amount, encodedCall).send({from: accounts[0]}); let receipt = await DAppStore.methods.dapps(0).call(); @@ -64,6 +65,7 @@ contract("DAppStore", function () { assert.strictEqual(developer, receipt.developer); assert.strictEqual(id, receipt.id); + assert.strictEqual(metadata, TestUtils.getIpfsHashFromBytes32(receipt.metadata)); // Check the DApp Store actually receives the SNT! let bal_receipt = await SNT.methods.balanceOf(DAppStore.options.address).call(); @@ -90,9 +92,10 @@ contract("DAppStore", function () { it("should not create a new DApp with the same ID", async function () { let id = "0x7465737400000000000000000000000000000000000000000000000000000000"; let amount = 1000; + let metadata = 'QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue'; await SNT.methods.generateTokens(accounts[0], amount).send(); - const encodedCall = DAppStore.methods.createDApp(id,amount).encodeABI(); + const encodedCall = DAppStore.methods.createDApp(id,amount, TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI(); try { await SNT.methods.approveAndCall(DAppStore.options.address, amount, encodedCall).send({from: accounts[0]}); @@ -104,13 +107,14 @@ contract("DAppStore", function () { it("should not create a new DApp when exceeding the ceiling or staking nothing", async function () { let id = "0x7465737400000000000000000000000000000000000000000000000000000000"; + let metadata = 'QmSmv5e5DYc2otwWcpUzuqmt389s3HHx651TbxDvKBFFue'; let initial = await DAppStore.methods.max().call(); let amount = parseInt(initial, 10); let amount0 = 0; await SNT.methods.generateTokens(accounts[0], amount).send(); - const encodedCall = DAppStore.methods.createDApp(id,amount).encodeABI(); + const encodedCall = DAppStore.methods.createDApp(id,amount,TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI(); try { await SNT.methods.approveAndCall(DAppStore.options.address, amount, encodedCall).send({from: accounts[0]}); assert.fail('should have reverted before'); @@ -118,7 +122,7 @@ contract("DAppStore", function () { TestUtils.assertJump(error); } - const encodedCall0 = DAppStore.methods.createDApp(id,amount0).encodeABI(); + const encodedCall0 = DAppStore.methods.createDApp(id,amount0,TestUtils.getBytes32FromIpfsHash(metadata)).encodeABI(); try { await SNT.methods.approveAndCall(DAppStore.options.address, amount0, encodedCall0).send({from: accounts[0]}); assert.fail('should have reverted before'); diff --git a/utils/testUtils.js b/utils/testUtils.js index 898c1b3..803b342 100644 --- a/utils/testUtils.js +++ b/utils/testUtils.js @@ -1,4 +1,5 @@ /*global assert, web3*/ +const bs58 = require('bs58'); // This has been tested with the real Ethereum network and Testrpc. // Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9 @@ -145,4 +146,17 @@ exports.assertReverts = (contractMethodCall, maxGasAvailable) => { exports.increaseTime = async (amount) => { await evmMethod("evm_increaseTime", [Number(amount)]); await evmMethod("evm_mine"); - }; \ No newline at end of file + }; + + +exports.getBytes32FromIpfsHash = ipfsListing => { + const decodedHash = bs58.decode(ipfsListing).slice(2).toString('hex') + return `0x${decodedHash}` +} + +exports.getIpfsHashFromBytes32 = bytes32Hex => { + const hashHex = `1220${bytes32Hex.slice(2)}` + const hashBytes = Buffer.from(hashHex, 'hex') + const hashStr = bs58.encode(hashBytes) + return hashStr +} \ No newline at end of file