From a4b1cd6e313a8315b8dacc755c25c12e2d365f3d Mon Sep 17 00:00:00 2001 From: AugustoL Date: Thu, 26 Oct 2017 19:48:29 -0400 Subject: [PATCH 01/13] Add SmartToken contract with tests and documentation add missing public identifier in approveData in SmartToken contract remove constact from showMessage function in message helper contract move Message helper contract to mocks folder move SmartTokenMock contract to mocks folder --- contracts/mocks/MessageHelper.sol | 25 +++ contracts/mocks/SmartTokenMock.sol | 15 ++ contracts/token/SmartToken.sol | 81 ++++++++ docs/source/SmartToken | 16 ++ test/SmartToken.js | 322 +++++++++++++++++++++++++++++ 5 files changed, 459 insertions(+) create mode 100644 contracts/mocks/MessageHelper.sol create mode 100644 contracts/mocks/SmartTokenMock.sol create mode 100644 contracts/token/SmartToken.sol create mode 100644 docs/source/SmartToken create mode 100644 test/SmartToken.js diff --git a/contracts/mocks/MessageHelper.sol b/contracts/mocks/MessageHelper.sol new file mode 100644 index 00000000000..5c864273c0a --- /dev/null +++ b/contracts/mocks/MessageHelper.sol @@ -0,0 +1,25 @@ +pragma solidity ^0.4.11; + +contract MessageHelper { + + event Show(bytes32 b32, uint256 number, string text); + + function showMessage( + bytes32 message, uint256 number, string text + ) returns (bool) { + Show(message, number, text); + return true; + } + + function fail() { + throw; + } + + function call(address to, bytes data) returns (bool) { + if (to.call(data)) + return true; + else + return false; + } + +} diff --git a/contracts/mocks/SmartTokenMock.sol b/contracts/mocks/SmartTokenMock.sol new file mode 100644 index 00000000000..37edbcee4b2 --- /dev/null +++ b/contracts/mocks/SmartTokenMock.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.13; + + +import '../token/SmartToken.sol'; + + +// mock class using SmartToken +contract SmartTokenMock is SmartToken { + + function SmartTokenMock(address initialAccount, uint256 initialBalance) { + balances[initialAccount] = initialBalance; + totalSupply = initialBalance; + } + +} diff --git a/contracts/token/SmartToken.sol b/contracts/token/SmartToken.sol new file mode 100644 index 00000000000..cc3ced30f7a --- /dev/null +++ b/contracts/token/SmartToken.sol @@ -0,0 +1,81 @@ +pragma solidity ^0.4.13; + +import "./StandardToken.sol"; + +/** + @title SmartToken, an extension of ERC20 token standard + + Implementation the SmartToken, following the ERC20 standard with extra + methods to transfer value and data and execute calls in transfers and + approvals. + Uses OpenZeppelin StandardToken. + */ +contract SmartToken is StandardToken { + + /** + @dev `approveData` is an addition to ERC20 token methods. It allows to + approve the transfer of value and execute a call with the sent data. + + Beware that changing an allowance with this method brings the risk that + someone may use both the old and the new allowance by unfortunate + transaction ordering. One possible solution to mitigate this race condition + is to first reduce the spender's allowance to 0 and set the desired value + afterwards: + https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + + @param _spender The address that will spend the funds. + @param _value The amount of tokens to be spent. + @param _data ABI-encoded contract call to call `_to` address. + + @return true if the call function was executed successfully + */ + function approveData(address _spender, uint256 _value, bytes _data) public returns (bool) { + require(_spender != address(this)); + + super.approve(_spender, _value); + + require(_spender.call(_data)); + + return true; + } + + /** + @dev Addition to ERC20 token methods. Transfer tokens to a specified + address and execute a call with the sent data on the same transaction + + @param _to address The address which you want to transfer to + @param _value uint256 the amout of tokens to be transfered + @param _data ABI-encoded contract call to call `_to` address. + + @return true if the call function was executed successfully + */ + function transferData(address _to, uint256 _value, bytes _data) public returns (bool) { + require(_to != address(this)); + + require(_to.call(_data)); + + super.transfer(_to, _value); + return true; + } + + /** + @dev Addition to ERC20 token methods. Transfer tokens from one address to + another and make a contract call on the same transaction + + @param _from The address which you want to send tokens from + @param _to The address which you want to transfer to + @param _value The amout of tokens to be transferred + @param _data ABI-encoded contract call to call `_to` address. + + @return true if the call function was executed successfully + */ + function transferDataFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { + require(_to != address(this)); + + require(_to.call(_data)); + + super.transferFrom(_from, _to, _value); + return true; + } + +} diff --git a/docs/source/SmartToken b/docs/source/SmartToken new file mode 100644 index 00000000000..016ef152bdd --- /dev/null +++ b/docs/source/SmartToken @@ -0,0 +1,16 @@ +SmartToken +============================================= + +Inherits from contract StandardToken. Implementation of a ERC20 compatible token with methods to transfer value and execute calls in transfers and approvals (see https://github.com/ethereum/EIPs/issues/20) + +approveData(address _spender, uint _value, bytes _data) returns (bool success) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +It allows to approve the transfer of value and execute a call with the sent data. + +function transferData(address _to, uint _value, bytes _data) returns (bool success) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Transfer tokens to a specified address and execute a call with the sent data on the same transaction + +transferDataFrom(address _from, address _to, uint _value, bytes _data) returns (bool success) +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Transfer tokens from one address to another and make a contract call on the same transaction \ No newline at end of file diff --git a/test/SmartToken.js b/test/SmartToken.js new file mode 100644 index 00000000000..2fd063c75e5 --- /dev/null +++ b/test/SmartToken.js @@ -0,0 +1,322 @@ +'use strict'; + +const assertJump = require('./helpers/assertJump'); +const expectThrow = require('./helpers/expectThrow'); +var Message = artifacts.require('./helpers/Message.sol'); +var SmartTokenMock = artifacts.require('./helpers/SmartTokenMock.sol'); + +var BigNumber = web3.BigNumber; + +require('chai') + .use(require('chai-bignumber')(BigNumber)) + .should(); + +contract('SmartToken', function(accounts) { + + let token; + + beforeEach(async function() { + token = await SmartTokenMock.new(accounts[0], 100); + }); + + it('should return the correct totalSupply after construction', async function() { + let totalSupply = await token.totalSupply(); + + assert.equal(totalSupply, 100); + }); + + it('should return the correct allowance amount after approval', async function() { + let token = await SmartTokenMock.new(); + await token.approve(accounts[1], 100); + let allowance = await token.allowance(accounts[0], accounts[1]); + + assert.equal(allowance, 100); + }); + + it('should return correct balances after transfer', async function() { + await token.transfer(accounts[1], 100); + let balance0 = await token.balanceOf(accounts[0]); + assert.equal(balance0, 0); + + let balance1 = await token.balanceOf(accounts[1]); + assert.equal(balance1, 100); + }); + + it('should throw an error when trying to transfer more than balance', async function() { + try { + await token.transfer(accounts[1], 101); + assert.fail('should have thrown before'); + } catch(error) { + assertJump(error); + } + }); + + it('should return correct balances after transfering from another account', async function() { + await token.approve(accounts[1], 100); + await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); + + let balance0 = await token.balanceOf(accounts[0]); + assert.equal(balance0, 0); + + let balance1 = await token.balanceOf(accounts[2]); + assert.equal(balance1, 100); + + let balance2 = await token.balanceOf(accounts[1]); + assert.equal(balance2, 0); + }); + + it('should throw an error when trying to transfer more than allowed', async function() { + await token.approve(accounts[1], 99); + try { + await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); + assert.fail('should have thrown before'); + } catch (error) { + assertJump(error); + } + }); + + it('should throw an error when trying to transferFrom more than _from has', async function() { + let balance0 = await token.balanceOf(accounts[0]); + await token.approve(accounts[1], 99); + try { + await token.transferFrom(accounts[0], accounts[2], balance0+1, {from: accounts[1]}); + assert.fail('should have thrown before'); + } catch (error) { + assertJump(error); + } + }); + + describe('validating allowance updates to spender', function() { + let preApproved; + + it('should start with zero', async function() { + preApproved = await token.allowance(accounts[0], accounts[1]); + assert.equal(preApproved, 0); + }) + + it('should increase by 50 then decrease by 10', async function() { + await token.increaseApproval(accounts[1], 50); + let postIncrease = await token.allowance(accounts[0], accounts[1]); + preApproved.plus(50).should.be.bignumber.equal(postIncrease); + await token.decreaseApproval(accounts[1], 10); + let postDecrease = await token.allowance(accounts[0], accounts[1]); + postIncrease.minus(10).should.be.bignumber.equal(postDecrease); + }) + }); + + it('should increase by 50 then set to 0 when decreasing by more than 50', async function() { + await token.approve(accounts[1], 50); + await token.decreaseApproval(accounts[1], 60); + let postDecrease = await token.allowance(accounts[0], accounts[1]); + postDecrease.should.be.bignumber.equal(0); + }); + + it('should throw an error when trying to transfer to 0x0', async function() { + try { + let transfer = await token.transfer(0x0, 100); + assert.fail('should have thrown before'); + } catch(error) { + assertJump(error); + } + }); + + it('should throw an error when trying to transferFrom to 0x0', async function() { + await token.approve(accounts[1], 100); + try { + let transfer = await token.transferFrom(accounts[0], 0x0, 100, {from: accounts[1]}); + assert.fail('should have thrown before'); + } catch(error) { + assertJump(error); + } + }); + + it('should return correct balances after approve and show the event on receiver contract', async function() { + let message = await Message.new(); + + let data = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + let transaction = await token.approveData( + message.contract.address, 100, data, {from: accounts[0]} + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + + }); + + it('should return correct balances after transferData and show the event on receiver contract', async function() { + let message = await Message.new(); + + let data = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + let transaction = await token.transferData( + message.contract.address, 100, data, {from: accounts[0]} + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.balanceOf(message.contract.address) + ); + + }); + + it('should return correct allowance after approveData and show the event on receiver contract', async function() { + let message = await Message.new(); + + let data = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + let transaction = await token.approveData( + message.contract.address, 100, data, {from: accounts[0]} + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + + }); + + it('should return correct balances after transferFrom and show the event on receiver contract', async function() { + let message = await Message.new(); + + let data = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + await token.approve(accounts[1], 100, {from: accounts[0]}); + + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], accounts[1]) + ); + + let transaction = await token.transferDataFrom( + accounts[0], message.contract.address, 100, data, {from: accounts[1]} + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.balanceOf(message.contract.address) + ); + + }); + + it('should fail inside approveData', async function() { + let message = await Message.new(); + + let data = message.contract.fail.getData(); + + try { + await token.approveData( + message.contract.address, 10, data, + {from: accounts[1]} + ); + assert(false, 'approveData should have raised'); + } catch(error) { + assertJump(error); + } + + // approval should not have gone through so allowance is still 0 + new BigNumber(0).should.be.bignumber + .equal(await token.allowance(accounts[1], message.contract.address)); + + }); + + it('should fail inside transferData', async function() { + let message = await Message.new(); + + let data = message.contract.fail.getData(); + + try { + await token.transferData( + message.contract.address, 10, data, + {from: accounts[0]} + ); + assert(false, 'transferData should have failed'); + } catch(error) { + assertJump(error); + } + + // transfer should not have gone through, so balance is still 0 + new BigNumber(0).should.be.bignumber + .equal(await token.balanceOf(message.contract.address)); + + }); + + it('should fail inside transferDataFrom', async function() { + let message = await Message.new(); + + let data = message.contract.fail.getData(); + + await token.approve(accounts[1], 10, {from: accounts[2]}); + + try { + await token.transferDataFrom( + accounts[2], message.contract.address, 10, data, + {from: accounts[1]} + ); + assert(false, 'transferDataFrom should have thrown'); + } catch(error) { + assertJump(error); + } + + // transferDataFrom should have failed so balance is still 0 but allowance is 10 + new BigNumber(10).should.be.bignumber + .equal(await token.allowance(accounts[2], accounts[1])); + new BigNumber(0).should.be.bignumber + .equal(await token.balanceOf(message.contract.address)); + + }); + + it('should fail approveData when using token contract address as receiver', async function() { + let data = token.contract.approve.getData(accounts[5], 66); + + try { + await token.approveData(token.contract.address, 100, data, {from: accounts[0]}); + assert(false, 'approveData should have thrown because the spender cannot be the token itself'); + } catch(error) { + assertJump(error); + } + + }); + + it('should fail transferData when using token contract address as receiver', async function() { + + try { + await token.transferData( + token.contract.address, 100, web3.toHex(0), {from: accounts[0]} + ); + assert(false, 'transferData should have thrown because the spender cannot be the token itself'); + } catch(error) { + assertJump(error); + } + + }); + + it('should fail transferDataFrom when using token contract address as receiver', async function() { + + await token.approve(accounts[1], 1, {from: accounts[0]}); + + try { + await token.transferDataFrom( + accounts[0], token.contract.address, 1, web3.toHex(0), {from: accounts[1]} + ); + assert(false, 'transferDataFrom should have thrown because the spender cannot be the token itself'); + } catch(error) { + assertJump(error); + } + + }); + +}); From a806520d6f0d9a02460980ef0a045f7bef26a1c0 Mon Sep 17 00:00:00 2001 From: AugustoL Date: Thu, 4 Jan 2018 16:36:42 -0300 Subject: [PATCH 02/13] change SmartToken test to work with new linter rules --- test/SmartToken.js | 207 ++++++++++++++++----------------------------- 1 file changed, 73 insertions(+), 134 deletions(-) diff --git a/test/SmartToken.js b/test/SmartToken.js index 2fd063c75e5..54c67665ca7 100644 --- a/test/SmartToken.js +++ b/test/SmartToken.js @@ -1,31 +1,29 @@ -'use strict'; -const assertJump = require('./helpers/assertJump'); -const expectThrow = require('./helpers/expectThrow'); -var Message = artifacts.require('./helpers/Message.sol'); -var SmartTokenMock = artifacts.require('./helpers/SmartTokenMock.sol'); +import EVMRevert from './helpers/EVMRevert'; +var Message = artifacts.require('./mock/MessageHelper.sol'); +var SmartTokenMock = artifacts.require('./mock/SmartTokenMock.sol'); var BigNumber = web3.BigNumber; require('chai') + .use(require('chai-as-promised')) .use(require('chai-bignumber')(BigNumber)) .should(); -contract('SmartToken', function(accounts) { - +contract('SmartToken', function (accounts) { let token; - beforeEach(async function() { + beforeEach(async function () { token = await SmartTokenMock.new(accounts[0], 100); }); - it('should return the correct totalSupply after construction', async function() { + it('should return the correct totalSupply after construction', async function () { let totalSupply = await token.totalSupply(); assert.equal(totalSupply, 100); }); - it('should return the correct allowance amount after approval', async function() { + it('should return the correct allowance amount after approval', async function () { let token = await SmartTokenMock.new(); await token.approve(accounts[1], 100); let allowance = await token.allowance(accounts[0], accounts[1]); @@ -33,7 +31,7 @@ contract('SmartToken', function(accounts) { assert.equal(allowance, 100); }); - it('should return correct balances after transfer', async function() { + it('should return correct balances after transfer', async function () { await token.transfer(accounts[1], 100); let balance0 = await token.balanceOf(accounts[0]); assert.equal(balance0, 0); @@ -42,18 +40,13 @@ contract('SmartToken', function(accounts) { assert.equal(balance1, 100); }); - it('should throw an error when trying to transfer more than balance', async function() { - try { - await token.transfer(accounts[1], 101); - assert.fail('should have thrown before'); - } catch(error) { - assertJump(error); - } + it('should throw an error when trying to transfer more than balance', async function () { + await token.transfer(accounts[1], 101).should.be.rejectedWith(EVMRevert); }); - it('should return correct balances after transfering from another account', async function() { + it('should return correct balances after transfering from another account', async function () { await token.approve(accounts[1], 100); - await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); + await token.transferFrom(accounts[0], accounts[2], 100, { from: accounts[1] }); let balance0 = await token.balanceOf(accounts[0]); assert.equal(balance0, 0); @@ -65,72 +58,59 @@ contract('SmartToken', function(accounts) { assert.equal(balance2, 0); }); - it('should throw an error when trying to transfer more than allowed', async function() { + it('should throw an error when trying to transfer more than allowed', async function () { await token.approve(accounts[1], 99); - try { - await token.transferFrom(accounts[0], accounts[2], 100, {from: accounts[1]}); - assert.fail('should have thrown before'); - } catch (error) { - assertJump(error); - } + await token.transferFrom( + accounts[0], accounts[2], 100, + { from: accounts[1] } + ).should.be.rejectedWith(EVMRevert); }); - it('should throw an error when trying to transferFrom more than _from has', async function() { + it('should throw an error when trying to transferFrom more than _from has', async function () { let balance0 = await token.balanceOf(accounts[0]); await token.approve(accounts[1], 99); - try { - await token.transferFrom(accounts[0], accounts[2], balance0+1, {from: accounts[1]}); - assert.fail('should have thrown before'); - } catch (error) { - assertJump(error); - } + await token.transferFrom( + accounts[0], accounts[2], balance0 + 1, + { from: accounts[1] } + ).should.be.rejectedWith(EVMRevert); }); - describe('validating allowance updates to spender', function() { + describe('validating allowance updates to spender', function () { let preApproved; - it('should start with zero', async function() { + it('should start with zero', async function () { preApproved = await token.allowance(accounts[0], accounts[1]); assert.equal(preApproved, 0); - }) + }); - it('should increase by 50 then decrease by 10', async function() { + it('should increase by 50 then decrease by 10', async function () { await token.increaseApproval(accounts[1], 50); let postIncrease = await token.allowance(accounts[0], accounts[1]); preApproved.plus(50).should.be.bignumber.equal(postIncrease); await token.decreaseApproval(accounts[1], 10); let postDecrease = await token.allowance(accounts[0], accounts[1]); postIncrease.minus(10).should.be.bignumber.equal(postDecrease); - }) + }); }); - it('should increase by 50 then set to 0 when decreasing by more than 50', async function() { + it('should increase by 50 then set to 0 when decreasing by more than 50', async function () { await token.approve(accounts[1], 50); await token.decreaseApproval(accounts[1], 60); let postDecrease = await token.allowance(accounts[0], accounts[1]); postDecrease.should.be.bignumber.equal(0); }); - it('should throw an error when trying to transfer to 0x0', async function() { - try { - let transfer = await token.transfer(0x0, 100); - assert.fail('should have thrown before'); - } catch(error) { - assertJump(error); - } + it('should throw an error when trying to transfer to 0x0', async function () { + await token.transfer(0x0, 100).should.be.rejectedWith(EVMRevert); }); - it('should throw an error when trying to transferFrom to 0x0', async function() { + it('should throw an error when trying to transferFrom to 0x0', async function () { await token.approve(accounts[1], 100); - try { - let transfer = await token.transferFrom(accounts[0], 0x0, 100, {from: accounts[1]}); - assert.fail('should have thrown before'); - } catch(error) { - assertJump(error); - } + await token.transferFrom(accounts[0], 0x0, 100, { from: accounts[1] }) + .should.be.rejectedWith(EVMRevert); }); - it('should return correct balances after approve and show the event on receiver contract', async function() { + it('should return correct balances after approve and show the event on receiver contract', async function () { let message = await Message.new(); let data = message.contract.showMessage.getData( @@ -138,7 +118,7 @@ contract('SmartToken', function(accounts) { ); let transaction = await token.approveData( - message.contract.address, 100, data, {from: accounts[0]} + message.contract.address, 100, data, { from: accounts[0] } ); assert.equal(2, transaction.receipt.logs.length); @@ -146,10 +126,9 @@ contract('SmartToken', function(accounts) { new BigNumber(100).should.be.bignumber.equal( await token.allowance(accounts[0], message.contract.address) ); - }); - it('should return correct balances after transferData and show the event on receiver contract', async function() { + it('should return correct balances after transferData and show the event on receiver contract', async function () { let message = await Message.new(); let data = message.contract.showMessage.getData( @@ -157,7 +136,7 @@ contract('SmartToken', function(accounts) { ); let transaction = await token.transferData( - message.contract.address, 100, data, {from: accounts[0]} + message.contract.address, 100, data, { from: accounts[0] } ); assert.equal(2, transaction.receipt.logs.length); @@ -165,10 +144,9 @@ contract('SmartToken', function(accounts) { new BigNumber(100).should.be.bignumber.equal( await token.balanceOf(message.contract.address) ); - }); - it('should return correct allowance after approveData and show the event on receiver contract', async function() { + it('should return correct allowance after approveData and show the event on receiver contract', async function () { let message = await Message.new(); let data = message.contract.showMessage.getData( @@ -176,7 +154,7 @@ contract('SmartToken', function(accounts) { ); let transaction = await token.approveData( - message.contract.address, 100, data, {from: accounts[0]} + message.contract.address, 100, data, { from: accounts[0] } ); assert.equal(2, transaction.receipt.logs.length); @@ -184,24 +162,23 @@ contract('SmartToken', function(accounts) { new BigNumber(100).should.be.bignumber.equal( await token.allowance(accounts[0], message.contract.address) ); - }); - it('should return correct balances after transferFrom and show the event on receiver contract', async function() { + it('should return correct balances after transferFrom and show the event on receiver contract', async function () { let message = await Message.new(); let data = message.contract.showMessage.getData( web3.toHex(123456), 666, 'Transfer Done' ); - await token.approve(accounts[1], 100, {from: accounts[0]}); + await token.approve(accounts[1], 100, { from: accounts[0] }); new BigNumber(100).should.be.bignumber.equal( await token.allowance(accounts[0], accounts[1]) ); let transaction = await token.transferDataFrom( - accounts[0], message.contract.address, 100, data, {from: accounts[1]} + accounts[0], message.contract.address, 100, data, { from: accounts[1] } ); assert.equal(2, transaction.receipt.logs.length); @@ -209,114 +186,76 @@ contract('SmartToken', function(accounts) { new BigNumber(100).should.be.bignumber.equal( await token.balanceOf(message.contract.address) ); - }); - it('should fail inside approveData', async function() { + it('should fail inside approveData', async function () { let message = await Message.new(); let data = message.contract.fail.getData(); - try { - await token.approveData( - message.contract.address, 10, data, - {from: accounts[1]} - ); - assert(false, 'approveData should have raised'); - } catch(error) { - assertJump(error); - } + await token.approveData( + message.contract.address, 10, data, + { from: accounts[1] } + ).should.be.rejectedWith(EVMRevert); // approval should not have gone through so allowance is still 0 new BigNumber(0).should.be.bignumber .equal(await token.allowance(accounts[1], message.contract.address)); - }); - it('should fail inside transferData', async function() { + it('should fail inside transferData', async function () { let message = await Message.new(); let data = message.contract.fail.getData(); - try { - await token.transferData( - message.contract.address, 10, data, - {from: accounts[0]} - ); - assert(false, 'transferData should have failed'); - } catch(error) { - assertJump(error); - } + await token.transferData( + message.contract.address, 10, data, + { from: accounts[0] } + ).should.be.rejectedWith(EVMRevert); // transfer should not have gone through, so balance is still 0 new BigNumber(0).should.be.bignumber .equal(await token.balanceOf(message.contract.address)); - }); - it('should fail inside transferDataFrom', async function() { + it('should fail inside transferDataFrom', async function () { let message = await Message.new(); let data = message.contract.fail.getData(); - await token.approve(accounts[1], 10, {from: accounts[2]}); + await token.approve(accounts[1], 10, { from: accounts[2] }); - try { - await token.transferDataFrom( - accounts[2], message.contract.address, 10, data, - {from: accounts[1]} - ); - assert(false, 'transferDataFrom should have thrown'); - } catch(error) { - assertJump(error); - } + await token.transferDataFrom( + accounts[2], message.contract.address, 10, data, + { from: accounts[1] } + ).should.be.rejectedWith(EVMRevert); // transferDataFrom should have failed so balance is still 0 but allowance is 10 new BigNumber(10).should.be.bignumber .equal(await token.allowance(accounts[2], accounts[1])); new BigNumber(0).should.be.bignumber .equal(await token.balanceOf(message.contract.address)); - }); - it('should fail approveData when using token contract address as receiver', async function() { + it('should fail approveData when using token contract address as receiver', async function () { let data = token.contract.approve.getData(accounts[5], 66); - try { - await token.approveData(token.contract.address, 100, data, {from: accounts[0]}); - assert(false, 'approveData should have thrown because the spender cannot be the token itself'); - } catch(error) { - assertJump(error); - } - + await token.approveData( + token.contract.address, 100, data, + { from: accounts[0] } + ).should.be.rejectedWith(EVMRevert); }); - it('should fail transferData when using token contract address as receiver', async function() { - - try { - await token.transferData( - token.contract.address, 100, web3.toHex(0), {from: accounts[0]} - ); - assert(false, 'transferData should have thrown because the spender cannot be the token itself'); - } catch(error) { - assertJump(error); - } - + it('should fail transferData when using token contract address as receiver', async function () { + await token.transferData( + token.contract.address, 100, web3.toHex(0), { from: accounts[0] } + ).should.be.rejectedWith(EVMRevert); }); - it('should fail transferDataFrom when using token contract address as receiver', async function() { - - await token.approve(accounts[1], 1, {from: accounts[0]}); - - try { - await token.transferDataFrom( - accounts[0], token.contract.address, 1, web3.toHex(0), {from: accounts[1]} - ); - assert(false, 'transferDataFrom should have thrown because the spender cannot be the token itself'); - } catch(error) { - assertJump(error); - } - + it('should fail transferDataFrom when using token contract address as receiver', async function () { + await token.approve(accounts[1], 1, { from: accounts[0] }); + await token.transferDataFrom( + accounts[0], token.contract.address, 1, web3.toHex(0), { from: accounts[1] } + ).should.be.rejectedWith(EVMRevert); }); - }); From e57f4be1fb52b93152b2221c661a27f94f6d15fe Mon Sep 17 00:00:00 2001 From: AugustoL Date: Thu, 11 Jan 2018 13:52:36 -0300 Subject: [PATCH 03/13] Rename SmartToken to ERC827 --- contracts/mocks/ERC827TokenMock.sol | 15 +++++++++++++++ contracts/mocks/SmartTokenMock.sol | 15 --------------- contracts/token/{SmartToken.sol => ERC827.sol} | 6 +++--- test/{SmartToken.js => ERC827Token.js} | 8 ++++---- 4 files changed, 22 insertions(+), 22 deletions(-) create mode 100644 contracts/mocks/ERC827TokenMock.sol delete mode 100644 contracts/mocks/SmartTokenMock.sol rename contracts/token/{SmartToken.sol => ERC827.sol} (93%) rename test/{SmartToken.js => ERC827Token.js} (97%) diff --git a/contracts/mocks/ERC827TokenMock.sol b/contracts/mocks/ERC827TokenMock.sol new file mode 100644 index 00000000000..1bc91174e96 --- /dev/null +++ b/contracts/mocks/ERC827TokenMock.sol @@ -0,0 +1,15 @@ +pragma solidity ^0.4.13; + + +import '../token/ERC827.sol'; + + +// mock class using ERC827 Token +contract ERC827TokenMock is ERC827 { + + function ERC827TokenMock(address initialAccount, uint256 initialBalance) { + balances[initialAccount] = initialBalance; + totalSupply = initialBalance; + } + +} diff --git a/contracts/mocks/SmartTokenMock.sol b/contracts/mocks/SmartTokenMock.sol deleted file mode 100644 index 37edbcee4b2..00000000000 --- a/contracts/mocks/SmartTokenMock.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.13; - - -import '../token/SmartToken.sol'; - - -// mock class using SmartToken -contract SmartTokenMock is SmartToken { - - function SmartTokenMock(address initialAccount, uint256 initialBalance) { - balances[initialAccount] = initialBalance; - totalSupply = initialBalance; - } - -} diff --git a/contracts/token/SmartToken.sol b/contracts/token/ERC827.sol similarity index 93% rename from contracts/token/SmartToken.sol rename to contracts/token/ERC827.sol index cc3ced30f7a..7729a26a722 100644 --- a/contracts/token/SmartToken.sol +++ b/contracts/token/ERC827.sol @@ -3,14 +3,14 @@ pragma solidity ^0.4.13; import "./StandardToken.sol"; /** - @title SmartToken, an extension of ERC20 token standard + @title ERC827, an extension of ERC20 token standard - Implementation the SmartToken, following the ERC20 standard with extra + Implementation the ERC827, following the ERC20 standard with extra methods to transfer value and data and execute calls in transfers and approvals. Uses OpenZeppelin StandardToken. */ -contract SmartToken is StandardToken { +contract ERC827 is StandardToken { /** @dev `approveData` is an addition to ERC20 token methods. It allows to diff --git a/test/SmartToken.js b/test/ERC827Token.js similarity index 97% rename from test/SmartToken.js rename to test/ERC827Token.js index 54c67665ca7..38ed7757043 100644 --- a/test/SmartToken.js +++ b/test/ERC827Token.js @@ -1,7 +1,7 @@ import EVMRevert from './helpers/EVMRevert'; var Message = artifacts.require('./mock/MessageHelper.sol'); -var SmartTokenMock = artifacts.require('./mock/SmartTokenMock.sol'); +var ERC827TokenMock = artifacts.require('./mock/ERC827TokenMock.sol'); var BigNumber = web3.BigNumber; @@ -10,11 +10,11 @@ require('chai') .use(require('chai-bignumber')(BigNumber)) .should(); -contract('SmartToken', function (accounts) { +contract('ERC827 Token', function (accounts) { let token; beforeEach(async function () { - token = await SmartTokenMock.new(accounts[0], 100); + token = await ERC827TokenMock.new(accounts[0], 100); }); it('should return the correct totalSupply after construction', async function () { @@ -24,7 +24,7 @@ contract('SmartToken', function (accounts) { }); it('should return the correct allowance amount after approval', async function () { - let token = await SmartTokenMock.new(); + let token = await ERC827TokenMock.new(); await token.approve(accounts[1], 100); let allowance = await token.allowance(accounts[0], accounts[1]); From f36f8e96dc5e939fb1d3d1a38c710fe03eef71e3 Mon Sep 17 00:00:00 2001 From: AugustoL Date: Thu, 11 Jan 2018 13:53:21 -0300 Subject: [PATCH 04/13] Delete SmartToken old docs --- docs/source/SmartToken | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 docs/source/SmartToken diff --git a/docs/source/SmartToken b/docs/source/SmartToken deleted file mode 100644 index 016ef152bdd..00000000000 --- a/docs/source/SmartToken +++ /dev/null @@ -1,16 +0,0 @@ -SmartToken -============================================= - -Inherits from contract StandardToken. Implementation of a ERC20 compatible token with methods to transfer value and execute calls in transfers and approvals (see https://github.com/ethereum/EIPs/issues/20) - -approveData(address _spender, uint _value, bytes _data) returns (bool success) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -It allows to approve the transfer of value and execute a call with the sent data. - -function transferData(address _to, uint _value, bytes _data) returns (bool success) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Transfer tokens to a specified address and execute a call with the sent data on the same transaction - -transferDataFrom(address _from, address _to, uint _value, bytes _data) returns (bool success) -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -Transfer tokens from one address to another and make a contract call on the same transaction \ No newline at end of file From 4ecdf312df10b51636154f5dc4c9c716eba4ff1c Mon Sep 17 00:00:00 2001 From: AugustoL Date: Thu, 11 Jan 2018 13:56:52 -0300 Subject: [PATCH 05/13] Change order of ERC20 methods and call in transferData and transferDataFrom --- contracts/token/ERC827.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/token/ERC827.sol b/contracts/token/ERC827.sol index 7729a26a722..c39e9dffedc 100644 --- a/contracts/token/ERC827.sol +++ b/contracts/token/ERC827.sol @@ -52,9 +52,9 @@ contract ERC827 is StandardToken { function transferData(address _to, uint256 _value, bytes _data) public returns (bool) { require(_to != address(this)); - require(_to.call(_data)); - super.transfer(_to, _value); + + require(_to.call(_data)); return true; } @@ -72,9 +72,9 @@ contract ERC827 is StandardToken { function transferDataFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { require(_to != address(this)); - require(_to.call(_data)); - super.transferFrom(_from, _to, _value); + + require(_to.call(_data)); return true; } From 7bd95b1e315474340126e1b1037efc44a80645ef Mon Sep 17 00:00:00 2001 From: AugustoL Date: Thu, 11 Jan 2018 16:33:33 -0300 Subject: [PATCH 06/13] Overload ERC20 funcitons with new _data argument --- contracts/token/ERC827.sol | 8 +- test/ERC827Token.js | 254 +++++++++++++++++++++---------------- 2 files changed, 148 insertions(+), 114 deletions(-) diff --git a/contracts/token/ERC827.sol b/contracts/token/ERC827.sol index c39e9dffedc..d07f65e8370 100644 --- a/contracts/token/ERC827.sol +++ b/contracts/token/ERC827.sol @@ -13,7 +13,7 @@ import "./StandardToken.sol"; contract ERC827 is StandardToken { /** - @dev `approveData` is an addition to ERC20 token methods. It allows to + @dev Addition to ERC20 token methods. It allows to approve the transfer of value and execute a call with the sent data. Beware that changing an allowance with this method brings the risk that @@ -29,7 +29,7 @@ contract ERC827 is StandardToken { @return true if the call function was executed successfully */ - function approveData(address _spender, uint256 _value, bytes _data) public returns (bool) { + function approve(address _spender, uint256 _value, bytes _data) public returns (bool) { require(_spender != address(this)); super.approve(_spender, _value); @@ -49,7 +49,7 @@ contract ERC827 is StandardToken { @return true if the call function was executed successfully */ - function transferData(address _to, uint256 _value, bytes _data) public returns (bool) { + function transfer(address _to, uint256 _value, bytes _data) public returns (bool) { require(_to != address(this)); super.transfer(_to, _value); @@ -69,7 +69,7 @@ contract ERC827 is StandardToken { @return true if the call function was executed successfully */ - function transferDataFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { + function transferFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { require(_to != address(this)); super.transferFrom(_from, _to, _value); diff --git a/test/ERC827Token.js b/test/ERC827Token.js index 38ed7757043..5c08d21328d 100644 --- a/test/ERC827Token.js +++ b/test/ERC827Token.js @@ -4,7 +4,7 @@ var Message = artifacts.require('./mock/MessageHelper.sol'); var ERC827TokenMock = artifacts.require('./mock/ERC827TokenMock.sol'); var BigNumber = web3.BigNumber; - +var ethjsABI = require('ethjs-abi'); require('chai') .use(require('chai-as-promised')) .use(require('chai-bignumber')(BigNumber)) @@ -110,152 +110,186 @@ contract('ERC827 Token', function (accounts) { .should.be.rejectedWith(EVMRevert); }); - it('should return correct balances after approve and show the event on receiver contract', async function () { - let message = await Message.new(); + describe('Test ERC827 methods', function () { - let data = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); + it('should return correct balances after transfer (with data) and show the event on receiver contract', async function () { + const message = await Message.new(); - let transaction = await token.approveData( - message.contract.address, 100, data, { from: accounts[0] } - ); + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); - assert.equal(2, transaction.receipt.logs.length); + // Use method #8 tranfer of the abi to encode the data tx + const transferData = ethjsABI.encodeMethod(token.abi[8], + [message.contract.address, 100, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[0], data: transferData } + ); - new BigNumber(100).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - }); + assert.equal(2, transaction.receipt.logs.length); - it('should return correct balances after transferData and show the event on receiver contract', async function () { - let message = await Message.new(); + new BigNumber(100).should.be.bignumber.equal( + await token.balanceOf(message.contract.address) + ); + }); - let data = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); + it('should return correct allowance after approve (with data) and show the event on receiver contract', async function () { + const message = await Message.new(); - let transaction = await token.transferData( - message.contract.address, 100, data, { from: accounts[0] } - ); + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); - assert.equal(2, transaction.receipt.logs.length); + // Use method #3 approve of the abi to encode the data tx + const approveData = ethjsABI.encodeMethod(token.abi[3], + [message.contract.address, 100, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[0], data: approveData } + ); - new BigNumber(100).should.be.bignumber.equal( - await token.balanceOf(message.contract.address) - ); - }); + assert.equal(2, transaction.receipt.logs.length); - it('should return correct allowance after approveData and show the event on receiver contract', async function () { - let message = await Message.new(); + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + }); - let data = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); + it('should return correct balances after transferFrom (with data) and show the event on receiver contract', async function () { + const message = await Message.new(); - let transaction = await token.approveData( - message.contract.address, 100, data, { from: accounts[0] } - ); + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); - assert.equal(2, transaction.receipt.logs.length); + await token.approve(accounts[1], 100, { from: accounts[0] }); - new BigNumber(100).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - }); + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], accounts[1]) + ); - it('should return correct balances after transferFrom and show the event on receiver contract', async function () { - let message = await Message.new(); + // Use method #7 transferFrom of the abi to encode the data tx + const transferFromData = ethjsABI.encodeMethod(token.abi[7], + [accounts[0], message.contract.address, 100, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[1], data: transferFromData } + ); - let data = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); + assert.equal(2, transaction.receipt.logs.length); - await token.approve(accounts[1], 100, { from: accounts[0] }); + new BigNumber(100).should.be.bignumber.equal( + await token.balanceOf(message.contract.address) + ); + }); - new BigNumber(100).should.be.bignumber.equal( - await token.allowance(accounts[0], accounts[1]) - ); + it('should fail inside approve (with data)', async function () { + const message = await Message.new(); - let transaction = await token.transferDataFrom( - accounts[0], message.contract.address, 100, data, { from: accounts[1] } - ); + const extraData = message.contract.fail.getData(); - assert.equal(2, transaction.receipt.logs.length); + // Use method #3 approve of the abi to encode the data tx + const approveData = ethjsABI.encodeMethod(token.abi[3], + [message.contract.address, 10, extraData] + ); + await token.sendTransaction( + { from: accounts[0], data: approveData } + ).should.be.rejectedWith(EVMRevert); - new BigNumber(100).should.be.bignumber.equal( - await token.balanceOf(message.contract.address) - ); - }); + // approval should not have gone through so allowance is still 0 + new BigNumber(0).should.be.bignumber + .equal(await token.allowance(accounts[1], message.contract.address)); + }); - it('should fail inside approveData', async function () { - let message = await Message.new(); + it('should fail inside transfer (with data)', async function () { + const message = await Message.new(); - let data = message.contract.fail.getData(); + const extraData = message.contract.fail.getData(); - await token.approveData( - message.contract.address, 10, data, - { from: accounts[1] } - ).should.be.rejectedWith(EVMRevert); + // Use method #8 tranfer of the abi to encode the data tx + const transferData = ethjsABI.encodeMethod(token.abi[8], + [message.contract.address, 10, extraData] + ); + await token.sendTransaction( + { from: accounts[0], data: transferData } + ).should.be.rejectedWith(EVMRevert); - // approval should not have gone through so allowance is still 0 - new BigNumber(0).should.be.bignumber - .equal(await token.allowance(accounts[1], message.contract.address)); - }); + // transfer should not have gone through, so balance is still 0 + new BigNumber(0).should.be.bignumber + .equal(await token.balanceOf(message.contract.address)); + }); - it('should fail inside transferData', async function () { - let message = await Message.new(); + it('should fail inside transferFrom (with data)', async function () { + const message = await Message.new(); - let data = message.contract.fail.getData(); + const extraData = message.contract.fail.getData(); - await token.transferData( - message.contract.address, 10, data, - { from: accounts[0] } - ).should.be.rejectedWith(EVMRevert); + await token.approve(accounts[1], 10, { from: accounts[2] }); - // transfer should not have gone through, so balance is still 0 - new BigNumber(0).should.be.bignumber - .equal(await token.balanceOf(message.contract.address)); - }); + // Use method #7 tranferFrom of the abi to encode the data tx + const transferFromData = ethjsABI.encodeMethod(token.abi[7], + [accounts[2], message.contract.address, 10, extraData] + ); + await token.sendTransaction( + { from: accounts[1], data: transferFromData } + ).should.be.rejectedWith(EVMRevert); - it('should fail inside transferDataFrom', async function () { - let message = await Message.new(); + // transferFrom should have failed so balance is still 0 but allowance is 10 + new BigNumber(10).should.be.bignumber + .equal(await token.allowance(accounts[2], accounts[1])); + new BigNumber(0).should.be.bignumber + .equal(await token.balanceOf(message.contract.address)); + }); - let data = message.contract.fail.getData(); + it('should fail approve (with data) when using token contract address as receiver', async function () { + const message = await Message.new(); - await token.approve(accounts[1], 10, { from: accounts[2] }); + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); - await token.transferDataFrom( - accounts[2], message.contract.address, 10, data, - { from: accounts[1] } - ).should.be.rejectedWith(EVMRevert); + // Use method #3 approve of the abi to encode the data tx + const approveData = ethjsABI.encodeMethod(token.abi[3], + [token.contract.address, 100, extraData] + ); + await token.sendTransaction( + { from: accounts[0], data: approveData } + ).should.be.rejectedWith(EVMRevert); + }); - // transferDataFrom should have failed so balance is still 0 but allowance is 10 - new BigNumber(10).should.be.bignumber - .equal(await token.allowance(accounts[2], accounts[1])); - new BigNumber(0).should.be.bignumber - .equal(await token.balanceOf(message.contract.address)); - }); + it('should fail transfer (with data) when using token contract address as receiver', async function () { + const message = await Message.new(); - it('should fail approveData when using token contract address as receiver', async function () { - let data = token.contract.approve.getData(accounts[5], 66); + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); - await token.approveData( - token.contract.address, 100, data, - { from: accounts[0] } - ).should.be.rejectedWith(EVMRevert); - }); + // Use method #8 tranfer of the abi to encode the data tx + const transferData = ethjsABI.encodeMethod(token.abi[8], + [token.contract.address, 100, extraData] + ); + await token.sendTransaction( + { from: accounts[0], data: transferData } + ).should.be.rejectedWith(EVMRevert); + }); - it('should fail transferData when using token contract address as receiver', async function () { - await token.transferData( - token.contract.address, 100, web3.toHex(0), { from: accounts[0] } - ).should.be.rejectedWith(EVMRevert); - }); + it('should fail transferFrom (with data) when using token contract address as receiver', async function () { + const message = await Message.new(); - it('should fail transferDataFrom when using token contract address as receiver', async function () { - await token.approve(accounts[1], 1, { from: accounts[0] }); - await token.transferDataFrom( - accounts[0], token.contract.address, 1, web3.toHex(0), { from: accounts[1] } - ).should.be.rejectedWith(EVMRevert); + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + await token.approve(accounts[1], 1, { from: accounts[0] }); + + // Use method #7 tranferFrom of the abi to encode the data tx + const transferFromData = ethjsABI.encodeMethod(token.abi[7], + [accounts[0], token.contract.address, 1, extraData] + ); + await token.sendTransaction( + { from: accounts[1], data: transferFromData } + ).should.be.rejectedWith(EVMRevert); + }); }); }); From e911b4d556c84b31d2dd3361021fa0b39061a3db Mon Sep 17 00:00:00 2001 From: AugustoL Date: Fri, 12 Jan 2018 13:08:55 -0300 Subject: [PATCH 07/13] Add findMethod function in ERC827Token test --- test/ERC827Token.js | 182 ++++++++++++++++++++++++-------------------- 1 file changed, 98 insertions(+), 84 deletions(-) diff --git a/test/ERC827Token.js b/test/ERC827Token.js index 5c08d21328d..08902f4493b 100644 --- a/test/ERC827Token.js +++ b/test/ERC827Token.js @@ -4,6 +4,7 @@ var Message = artifacts.require('./mock/MessageHelper.sol'); var ERC827TokenMock = artifacts.require('./mock/ERC827TokenMock.sol'); var BigNumber = web3.BigNumber; +var _ = require('lodash'); var ethjsABI = require('ethjs-abi'); require('chai') .use(require('chai-as-promised')) @@ -13,6 +14,15 @@ require('chai') contract('ERC827 Token', function (accounts) { let token; + function findMethod (abi, name, args) { + for (var i = 0; i < abi.length; i++) { + const methodArgs = _.map(abi[i].inputs, 'type').join(','); + if ((abi[i].name === name) && (methodArgs === args)) { + return abi[i]; + } + } + } + beforeEach(async function () { token = await ERC827TokenMock.new(accounts[0], 100); }); @@ -111,86 +121,90 @@ contract('ERC827 Token', function (accounts) { }); describe('Test ERC827 methods', function () { - - it('should return correct balances after transfer (with data) and show the event on receiver contract', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - // Use method #8 tranfer of the abi to encode the data tx - const transferData = ethjsABI.encodeMethod(token.abi[8], - [message.contract.address, 100, extraData] - ); - const transaction = await token.sendTransaction( - { from: accounts[0], data: transferData } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(100).should.be.bignumber.equal( - await token.balanceOf(message.contract.address) - ); - }); - - it('should return correct allowance after approve (with data) and show the event on receiver contract', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - // Use method #3 approve of the abi to encode the data tx - const approveData = ethjsABI.encodeMethod(token.abi[3], - [message.contract.address, 100, extraData] - ); - const transaction = await token.sendTransaction( - { from: accounts[0], data: approveData } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(100).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - }); - - it('should return correct balances after transferFrom (with data) and show the event on receiver contract', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.approve(accounts[1], 100, { from: accounts[0] }); - - new BigNumber(100).should.be.bignumber.equal( - await token.allowance(accounts[0], accounts[1]) - ); - - // Use method #7 transferFrom of the abi to encode the data tx - const transferFromData = ethjsABI.encodeMethod(token.abi[7], - [accounts[0], message.contract.address, 100, extraData] - ); - const transaction = await token.sendTransaction( - { from: accounts[1], data: transferFromData } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(100).should.be.bignumber.equal( - await token.balanceOf(message.contract.address) - ); - }); + it( + 'should return correct balances after transfer (with data) and show the event on receiver contract' + , async function () { + const message = await Message.new(); + + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes'); + const transferData = ethjsABI.encodeMethod(abiMethod, + [message.contract.address, 100, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[0], data: transferData } + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.balanceOf(message.contract.address) + ); + }); + + it( + 'should return correct allowance after approve (with data) and show the event on receiver contract' + , async function () { + const message = await Message.new(); + + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes'); + const approveData = ethjsABI.encodeMethod(abiMethod, + [message.contract.address, 100, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[0], data: approveData } + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + }); + + it( + 'should return correct balances after transferFrom (with data) and show the event on receiver contract' + , async function () { + const message = await Message.new(); + + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + await token.approve(accounts[1], 100, { from: accounts[0] }); + + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], accounts[1]) + ); + + const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes'); + const transferFromData = ethjsABI.encodeMethod(abiMethod, + [accounts[0], message.contract.address, 100, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[1], data: transferFromData } + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(100).should.be.bignumber.equal( + await token.balanceOf(message.contract.address) + ); + }); it('should fail inside approve (with data)', async function () { const message = await Message.new(); const extraData = message.contract.fail.getData(); - // Use method #3 approve of the abi to encode the data tx - const approveData = ethjsABI.encodeMethod(token.abi[3], + const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes'); + const approveData = ethjsABI.encodeMethod(abiMethod, [message.contract.address, 10, extraData] ); await token.sendTransaction( @@ -207,8 +221,8 @@ contract('ERC827 Token', function (accounts) { const extraData = message.contract.fail.getData(); - // Use method #8 tranfer of the abi to encode the data tx - const transferData = ethjsABI.encodeMethod(token.abi[8], + const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes'); + const transferData = ethjsABI.encodeMethod(abiMethod, [message.contract.address, 10, extraData] ); await token.sendTransaction( @@ -227,8 +241,8 @@ contract('ERC827 Token', function (accounts) { await token.approve(accounts[1], 10, { from: accounts[2] }); - // Use method #7 tranferFrom of the abi to encode the data tx - const transferFromData = ethjsABI.encodeMethod(token.abi[7], + const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes'); + const transferFromData = ethjsABI.encodeMethod(abiMethod, [accounts[2], message.contract.address, 10, extraData] ); await token.sendTransaction( @@ -249,8 +263,8 @@ contract('ERC827 Token', function (accounts) { web3.toHex(123456), 666, 'Transfer Done' ); - // Use method #3 approve of the abi to encode the data tx - const approveData = ethjsABI.encodeMethod(token.abi[3], + const abiMethod = findMethod(token.abi, 'approve', 'address,uint256,bytes'); + const approveData = ethjsABI.encodeMethod(abiMethod, [token.contract.address, 100, extraData] ); await token.sendTransaction( @@ -265,8 +279,8 @@ contract('ERC827 Token', function (accounts) { web3.toHex(123456), 666, 'Transfer Done' ); - // Use method #8 tranfer of the abi to encode the data tx - const transferData = ethjsABI.encodeMethod(token.abi[8], + const abiMethod = findMethod(token.abi, 'transfer', 'address,uint256,bytes'); + const transferData = ethjsABI.encodeMethod(abiMethod, [token.contract.address, 100, extraData] ); await token.sendTransaction( @@ -283,8 +297,8 @@ contract('ERC827 Token', function (accounts) { await token.approve(accounts[1], 1, { from: accounts[0] }); - // Use method #7 tranferFrom of the abi to encode the data tx - const transferFromData = ethjsABI.encodeMethod(token.abi[7], + const abiMethod = findMethod(token.abi, 'transferFrom', 'address,address,uint256,bytes'); + const transferFromData = ethjsABI.encodeMethod(abiMethod, [accounts[0], token.contract.address, 1, extraData] ); await token.sendTransaction( From 685d2087caeb52e6d1f868b9bcce404cae3e315f Mon Sep 17 00:00:00 2001 From: AugustoL Date: Mon, 15 Jan 2018 20:56:25 -0300 Subject: [PATCH 08/13] Add increase and decrease approval functions to ERC827 with tests --- contracts/token/ERC827.sol | 44 +++++++++++++++++++++++++++++ test/ERC827Token.js | 58 +++++++++++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/contracts/token/ERC827.sol b/contracts/token/ERC827.sol index d07f65e8370..472b82b0796 100644 --- a/contracts/token/ERC827.sol +++ b/contracts/token/ERC827.sol @@ -78,4 +78,48 @@ contract ERC827 is StandardToken { return true; } + /** + * @dev Addition to StandardToken methods. Increase the amount of tokens that + * an owner allowed to a spender and execute a call with the sent data. + * + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + * @param _data ABI-encoded contract call to call `_spender` address. + */ + function increaseApproval(address _spender, uint _addedValue, bytes _data) public returns (bool) { + require(_spender != address(this)); + + super.approve(_spender, _addedValue); + + require(_spender.call(_data)); + + return true; + } + + /** + * @dev Addition to StandardToken methods. Decrease the amount of tokens that + * an owner allowed to a spender and execute a call with the sent data. + * + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + * @param _data ABI-encoded contract call to call `_spender` address. + */ + function decreaseApproval(address _spender, uint _subtractedValue, bytes _data) public returns (bool) { + require(_spender != address(this)); + + super.decreaseApproval(_spender, _subtractedValue); + + require(_spender.call(_data)); + + return true; + } + } diff --git a/test/ERC827Token.js b/test/ERC827Token.js index 08902f4493b..7cb4ed26c44 100644 --- a/test/ERC827Token.js +++ b/test/ERC827Token.js @@ -94,7 +94,13 @@ contract('ERC827 Token', function (accounts) { }); it('should increase by 50 then decrease by 10', async function () { - await token.increaseApproval(accounts[1], 50); + const abiMethod = findMethod(token.abi, 'increaseApproval', 'address,uint256'); + const increaseApprovalData = ethjsABI.encodeMethod(abiMethod, + [accounts[1], 50] + ); + await token.sendTransaction( + { from: accounts[0], data: increaseApprovalData } + ); let postIncrease = await token.allowance(accounts[0], accounts[1]); preApproved.plus(50).should.be.bignumber.equal(postIncrease); await token.decreaseApproval(accounts[1], 10); @@ -168,6 +174,56 @@ contract('ERC827 Token', function (accounts) { ); }); + it( + 'should return correct allowance after increaseApproval (with data) and show the event on receiver contract' + , async function () { + const message = await Message.new(); + + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + const abiMethod = findMethod(token.abi, 'increaseApproval', 'address,uint256,bytes'); + const increaseApprovalData = ethjsABI.encodeMethod(abiMethod, + [message.contract.address, 50, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[0], data: increaseApprovalData } + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(50).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + }); + + it( + 'should return correct allowance after decreaseApproval (with data) and show the event on receiver contract' + , async function () { + const message = await Message.new(); + + await token.approve(message.contract.address, 100); + + const extraData = message.contract.showMessage.getData( + web3.toHex(123456), 666, 'Transfer Done' + ); + + const abiMethod = findMethod(token.abi, 'decreaseApproval', 'address,uint256,bytes'); + const decreaseApprovalData = ethjsABI.encodeMethod(abiMethod, + [message.contract.address, 60, extraData] + ); + const transaction = await token.sendTransaction( + { from: accounts[0], data: decreaseApprovalData } + ); + + assert.equal(2, transaction.receipt.logs.length); + + new BigNumber(40).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + }); + it( 'should return correct balances after transferFrom (with data) and show the event on receiver contract' , async function () { From 8854966847ae7fee32550a430465d92b6f5db6e8 Mon Sep 17 00:00:00 2001 From: AugustoL Date: Mon, 15 Jan 2018 21:15:21 -0300 Subject: [PATCH 09/13] change throw for require in MessageHelper contract@ --- contracts/mocks/MessageHelper.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mocks/MessageHelper.sol b/contracts/mocks/MessageHelper.sol index 5c864273c0a..0b137ee79bc 100644 --- a/contracts/mocks/MessageHelper.sol +++ b/contracts/mocks/MessageHelper.sol @@ -12,7 +12,7 @@ contract MessageHelper { } function fail() { - throw; + require(false); } function call(address to, bytes data) returns (bool) { From 87f5916341f48042713ef602adf3a25e26126835 Mon Sep 17 00:00:00 2001 From: AugustoL Date: Mon, 15 Jan 2018 21:17:32 -0300 Subject: [PATCH 10/13] Separate ERC827 interface in another contract --- contracts/mocks/ERC827TokenMock.sol | 4 +- contracts/token/ERC827.sol | 125 +++------------------------ contracts/token/ERC827Token.sol | 126 ++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 114 deletions(-) create mode 100644 contracts/token/ERC827Token.sol diff --git a/contracts/mocks/ERC827TokenMock.sol b/contracts/mocks/ERC827TokenMock.sol index 1bc91174e96..fbba4b5a576 100644 --- a/contracts/mocks/ERC827TokenMock.sol +++ b/contracts/mocks/ERC827TokenMock.sol @@ -1,11 +1,11 @@ pragma solidity ^0.4.13; -import '../token/ERC827.sol'; +import '../token/ERC827Token.sol'; // mock class using ERC827 Token -contract ERC827TokenMock is ERC827 { +contract ERC827TokenMock is ERC827Token { function ERC827TokenMock(address initialAccount, uint256 initialBalance) { balances[initialAccount] = initialBalance; diff --git a/contracts/token/ERC827.sol b/contracts/token/ERC827.sol index 472b82b0796..6bd217e4f61 100644 --- a/contracts/token/ERC827.sol +++ b/contracts/token/ERC827.sol @@ -1,125 +1,26 @@ pragma solidity ^0.4.13; -import "./StandardToken.sol"; +import "./ERC20.sol"; /** - @title ERC827, an extension of ERC20 token standard + @title ERC827 interface, an extension of ERC20 token standard - Implementation the ERC827, following the ERC20 standard with extra + Interface of a ERC827 token, following the ERC20 standard with extra methods to transfer value and data and execute calls in transfers and approvals. - Uses OpenZeppelin StandardToken. */ -contract ERC827 is StandardToken { +contract ERC827 is ERC20 { - /** - @dev Addition to ERC20 token methods. It allows to - approve the transfer of value and execute a call with the sent data. + function approve( + address _spender, uint256 _value, bytes _data + ) public returns (bool); - Beware that changing an allowance with this method brings the risk that - someone may use both the old and the new allowance by unfortunate - transaction ordering. One possible solution to mitigate this race condition - is to first reduce the spender's allowance to 0 and set the desired value - afterwards: - https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function transfer( + address _to, uint256 _value, bytes _data + ) public returns (bool); - @param _spender The address that will spend the funds. - @param _value The amount of tokens to be spent. - @param _data ABI-encoded contract call to call `_to` address. - - @return true if the call function was executed successfully - */ - function approve(address _spender, uint256 _value, bytes _data) public returns (bool) { - require(_spender != address(this)); - - super.approve(_spender, _value); - - require(_spender.call(_data)); - - return true; - } - - /** - @dev Addition to ERC20 token methods. Transfer tokens to a specified - address and execute a call with the sent data on the same transaction - - @param _to address The address which you want to transfer to - @param _value uint256 the amout of tokens to be transfered - @param _data ABI-encoded contract call to call `_to` address. - - @return true if the call function was executed successfully - */ - function transfer(address _to, uint256 _value, bytes _data) public returns (bool) { - require(_to != address(this)); - - super.transfer(_to, _value); - - require(_to.call(_data)); - return true; - } - - /** - @dev Addition to ERC20 token methods. Transfer tokens from one address to - another and make a contract call on the same transaction - - @param _from The address which you want to send tokens from - @param _to The address which you want to transfer to - @param _value The amout of tokens to be transferred - @param _data ABI-encoded contract call to call `_to` address. - - @return true if the call function was executed successfully - */ - function transferFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { - require(_to != address(this)); - - super.transferFrom(_from, _to, _value); - - require(_to.call(_data)); - return true; - } - - /** - * @dev Addition to StandardToken methods. Increase the amount of tokens that - * an owner allowed to a spender and execute a call with the sent data. - * - * approve should be called when allowed[_spender] == 0. To increment - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * @param _spender The address which will spend the funds. - * @param _addedValue The amount of tokens to increase the allowance by. - * @param _data ABI-encoded contract call to call `_spender` address. - */ - function increaseApproval(address _spender, uint _addedValue, bytes _data) public returns (bool) { - require(_spender != address(this)); - - super.approve(_spender, _addedValue); - - require(_spender.call(_data)); - - return true; - } - - /** - * @dev Addition to StandardToken methods. Decrease the amount of tokens that - * an owner allowed to a spender and execute a call with the sent data. - * - * approve should be called when allowed[_spender] == 0. To decrement - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * @param _spender The address which will spend the funds. - * @param _subtractedValue The amount of tokens to decrease the allowance by. - * @param _data ABI-encoded contract call to call `_spender` address. - */ - function decreaseApproval(address _spender, uint _subtractedValue, bytes _data) public returns (bool) { - require(_spender != address(this)); - - super.decreaseApproval(_spender, _subtractedValue); - - require(_spender.call(_data)); - - return true; - } + function transferFrom( + address _from, address _to, uint256 _value, bytes _data + ) public returns (bool); } diff --git a/contracts/token/ERC827Token.sol b/contracts/token/ERC827Token.sol new file mode 100644 index 00000000000..3cb22943dfd --- /dev/null +++ b/contracts/token/ERC827Token.sol @@ -0,0 +1,126 @@ +pragma solidity ^0.4.13; + +import "./ERC827.sol"; +import "./StandardToken.sol"; + +/** + @title ERC827, an extension of ERC20 token standard + + Implementation the ERC827, following the ERC20 standard with extra + methods to transfer value and data and execute calls in transfers and + approvals. + Uses OpenZeppelin StandardToken. + */ +contract ERC827Token is ERC827, StandardToken { + + /** + @dev Addition to ERC20 token methods. It allows to + approve the transfer of value and execute a call with the sent data. + + Beware that changing an allowance with this method brings the risk that + someone may use both the old and the new allowance by unfortunate + transaction ordering. One possible solution to mitigate this race condition + is to first reduce the spender's allowance to 0 and set the desired value + afterwards: + https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + + @param _spender The address that will spend the funds. + @param _value The amount of tokens to be spent. + @param _data ABI-encoded contract call to call `_to` address. + + @return true if the call function was executed successfully + */ + function approve(address _spender, uint256 _value, bytes _data) public returns (bool) { + require(_spender != address(this)); + + super.approve(_spender, _value); + + require(_spender.call(_data)); + + return true; + } + + /** + @dev Addition to ERC20 token methods. Transfer tokens to a specified + address and execute a call with the sent data on the same transaction + + @param _to address The address which you want to transfer to + @param _value uint256 the amout of tokens to be transfered + @param _data ABI-encoded contract call to call `_to` address. + + @return true if the call function was executed successfully + */ + function transfer(address _to, uint256 _value, bytes _data) public returns (bool) { + require(_to != address(this)); + + super.transfer(_to, _value); + + require(_to.call(_data)); + return true; + } + + /** + @dev Addition to ERC20 token methods. Transfer tokens from one address to + another and make a contract call on the same transaction + + @param _from The address which you want to send tokens from + @param _to The address which you want to transfer to + @param _value The amout of tokens to be transferred + @param _data ABI-encoded contract call to call `_to` address. + + @return true if the call function was executed successfully + */ + function transferFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) { + require(_to != address(this)); + + super.transferFrom(_from, _to, _value); + + require(_to.call(_data)); + return true; + } + + /** + * @dev Addition to StandardToken methods. Increase the amount of tokens that + * an owner allowed to a spender and execute a call with the sent data. + * + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + * @param _data ABI-encoded contract call to call `_spender` address. + */ + function increaseApproval(address _spender, uint _addedValue, bytes _data) public returns (bool) { + require(_spender != address(this)); + + super.approve(_spender, _addedValue); + + require(_spender.call(_data)); + + return true; + } + + /** + * @dev Addition to StandardToken methods. Decrease the amount of tokens that + * an owner allowed to a spender and execute a call with the sent data. + * + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + * @param _data ABI-encoded contract call to call `_spender` address. + */ + function decreaseApproval(address _spender, uint _subtractedValue, bytes _data) public returns (bool) { + require(_spender != address(this)); + + super.decreaseApproval(_spender, _subtractedValue); + + require(_spender.call(_data)); + + return true; + } + +} From 7ddd66fb744c55ee8b7cc251b2ac0c141fa34c5c Mon Sep 17 00:00:00 2001 From: AugustoL Date: Tue, 16 Jan 2018 18:43:50 -0300 Subject: [PATCH 11/13] fix increaseApproval in ERC827Token with tests --- contracts/token/ERC827Token.sol | 2 +- test/ERC827Token.js | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC827Token.sol b/contracts/token/ERC827Token.sol index 3cb22943dfd..173acf98f46 100644 --- a/contracts/token/ERC827Token.sol +++ b/contracts/token/ERC827Token.sol @@ -94,7 +94,7 @@ contract ERC827Token is ERC827, StandardToken { function increaseApproval(address _spender, uint _addedValue, bytes _data) public returns (bool) { require(_spender != address(this)); - super.approve(_spender, _addedValue); + super.increaseApproval(_spender, _addedValue); require(_spender.call(_data)); diff --git a/test/ERC827Token.js b/test/ERC827Token.js index 7cb4ed26c44..a88540ba6b6 100644 --- a/test/ERC827Token.js +++ b/test/ERC827Token.js @@ -183,6 +183,11 @@ contract('ERC827 Token', function (accounts) { web3.toHex(123456), 666, 'Transfer Done' ); + await token.approve(message.contract.address, 10); + new BigNumber(10).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + const abiMethod = findMethod(token.abi, 'increaseApproval', 'address,uint256,bytes'); const increaseApprovalData = ethjsABI.encodeMethod(abiMethod, [message.contract.address, 50, extraData] @@ -193,7 +198,7 @@ contract('ERC827 Token', function (accounts) { assert.equal(2, transaction.receipt.logs.length); - new BigNumber(50).should.be.bignumber.equal( + new BigNumber(60).should.be.bignumber.equal( await token.allowance(accounts[0], message.contract.address) ); }); @@ -205,6 +210,10 @@ contract('ERC827 Token', function (accounts) { await token.approve(message.contract.address, 100); + new BigNumber(100).should.be.bignumber.equal( + await token.allowance(accounts[0], message.contract.address) + ); + const extraData = message.contract.showMessage.getData( web3.toHex(123456), 666, 'Transfer Done' ); From 2b008f4cb6eb0942ab4d71d75d906291c79be31b Mon Sep 17 00:00:00 2001 From: AugustoL Date: Wed, 17 Jan 2018 11:21:25 -0300 Subject: [PATCH 12/13] Fix solidity linter errors --- contracts/mocks/ERC827TokenMock.sol | 4 ++-- contracts/mocks/MessageHelper.sol | 8 +++----- contracts/token/ERC827.sol | 16 +++++----------- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/contracts/mocks/ERC827TokenMock.sol b/contracts/mocks/ERC827TokenMock.sol index fbba4b5a576..8408d80e09a 100644 --- a/contracts/mocks/ERC827TokenMock.sol +++ b/contracts/mocks/ERC827TokenMock.sol @@ -1,13 +1,13 @@ pragma solidity ^0.4.13; -import '../token/ERC827Token.sol'; +import "../token/ERC827Token.sol"; // mock class using ERC827 Token contract ERC827TokenMock is ERC827Token { - function ERC827TokenMock(address initialAccount, uint256 initialBalance) { + function ERC827TokenMock(address initialAccount, uint256 initialBalance) public { balances[initialAccount] = initialBalance; totalSupply = initialBalance; } diff --git a/contracts/mocks/MessageHelper.sol b/contracts/mocks/MessageHelper.sol index 0b137ee79bc..f990241dab0 100644 --- a/contracts/mocks/MessageHelper.sol +++ b/contracts/mocks/MessageHelper.sol @@ -4,18 +4,16 @@ contract MessageHelper { event Show(bytes32 b32, uint256 number, string text); - function showMessage( - bytes32 message, uint256 number, string text - ) returns (bool) { + function showMessage( bytes32 message, uint256 number, string text ) public returns (bool) { Show(message, number, text); return true; } - function fail() { + function fail() public { require(false); } - function call(address to, bytes data) returns (bool) { + function call(address to, bytes data) public returns (bool) { if (to.call(data)) return true; else diff --git a/contracts/token/ERC827.sol b/contracts/token/ERC827.sol index 6bd217e4f61..f0793e607a0 100644 --- a/contracts/token/ERC827.sol +++ b/contracts/token/ERC827.sol @@ -1,7 +1,9 @@ pragma solidity ^0.4.13; + import "./ERC20.sol"; + /** @title ERC827 interface, an extension of ERC20 token standard @@ -11,16 +13,8 @@ import "./ERC20.sol"; */ contract ERC827 is ERC20 { - function approve( - address _spender, uint256 _value, bytes _data - ) public returns (bool); - - function transfer( - address _to, uint256 _value, bytes _data - ) public returns (bool); - - function transferFrom( - address _from, address _to, uint256 _value, bytes _data - ) public returns (bool); + function approve( address _spender, uint256 _value, bytes _data ) public returns (bool); + function transfer( address _to, uint256 _value, bytes _data ) public returns (bool); + function transferFrom( address _from, address _to, uint256 _value, bytes _data ) public returns (bool); } From 969466b8fd0f38b5a7d4545186193e8f7cfe4cc6 Mon Sep 17 00:00:00 2001 From: AugustoL Date: Wed, 17 Jan 2018 11:22:09 -0300 Subject: [PATCH 13/13] Add ethjs-abi dependency needed in ERC827 tests --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f15f6397b2b..6d93e41e1c5 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "truffle-hdwallet-provider": "0.0.3" }, "dependencies": { - "dotenv": "^4.0.0" + "dotenv": "^4.0.0", + "ethjs-abi": "^0.2.1" } }