From 6b37ba36a1d3a96dcb06a28ddcbfc191695264da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20G=C3=B3rski?= Date: Thu, 28 Jun 2018 18:32:07 +0200 Subject: [PATCH] Remove ERC827 token. (#1045) Implementing this token is unsafe as per comments here: https://github.com/ethereum/EIPs/issues/827#issuecomment-397857455 --- contracts/mocks/ERC827TokenMock.sol | 15 - contracts/token/ERC827/ERC827.sol | 42 --- contracts/token/ERC827/ERC827Token.sol | 163 --------- test/token/ERC827/ERC827Token.js | 489 ------------------------- 4 files changed, 709 deletions(-) delete mode 100644 contracts/mocks/ERC827TokenMock.sol delete mode 100644 contracts/token/ERC827/ERC827.sol delete mode 100644 contracts/token/ERC827/ERC827Token.sol delete mode 100644 test/token/ERC827/ERC827Token.js diff --git a/contracts/mocks/ERC827TokenMock.sol b/contracts/mocks/ERC827TokenMock.sol deleted file mode 100644 index 8bce91798..000000000 --- a/contracts/mocks/ERC827TokenMock.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.24; - - -import "../token/ERC827/ERC827Token.sol"; - - -// mock class using ERC827 Token -contract ERC827TokenMock is ERC827Token { - - constructor(address initialAccount, uint256 initialBalance) public { - balances[initialAccount] = initialBalance; - totalSupply_ = initialBalance; - } - -} diff --git a/contracts/token/ERC827/ERC827.sol b/contracts/token/ERC827/ERC827.sol deleted file mode 100644 index a283e2aa6..000000000 --- a/contracts/token/ERC827/ERC827.sol +++ /dev/null @@ -1,42 +0,0 @@ -pragma solidity ^0.4.24; - - -import "../ERC20/ERC20.sol"; - - -/** - * @title ERC827 interface, an extension of ERC20 token standard - * - * @dev Interface of a ERC827 token, following the ERC20 standard with extra - * methods to transfer value and data and execute calls in transfers and - * approvals. - */ -contract ERC827 is ERC20 { - function approveAndCall( - address _spender, - uint256 _value, - bytes _data - ) - public - payable - returns (bool); - - function transferAndCall( - address _to, - uint256 _value, - bytes _data - ) - public - payable - returns (bool); - - function transferFromAndCall( - address _from, - address _to, - uint256 _value, - bytes _data - ) - public - payable - returns (bool); -} diff --git a/contracts/token/ERC827/ERC827Token.sol b/contracts/token/ERC827/ERC827Token.sol deleted file mode 100644 index cb24d6a50..000000000 --- a/contracts/token/ERC827/ERC827Token.sol +++ /dev/null @@ -1,163 +0,0 @@ -/* solium-disable security/no-low-level-calls */ - -pragma solidity ^0.4.24; - -import "./ERC827.sol"; -import "../ERC20/StandardToken.sol"; - - -/** - * @title ERC827, an extension of ERC20 token standard - * - * @dev 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 `_spender` address. - * @return true if the call function was executed successfully - */ - function approveAndCall( - address _spender, - uint256 _value, - bytes _data - ) - public - payable - returns (bool) - { - require(_spender != address(this)); - - super.approve(_spender, _value); - - // solium-disable-next-line security/no-call-value - require(_spender.call.value(msg.value)(_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 transferAndCall( - address _to, - uint256 _value, - bytes _data - ) - public - payable - returns (bool) - { - require(_to != address(this)); - - super.transfer(_to, _value); - - // solium-disable-next-line security/no-call-value - require(_to.call.value(msg.value)(_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 transferFromAndCall( - address _from, - address _to, - uint256 _value, - bytes _data - ) - public payable returns (bool) - { - require(_to != address(this)); - - super.transferFrom(_from, _to, _value); - - // solium-disable-next-line security/no-call-value - require(_to.call.value(msg.value)(_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 increaseApprovalAndCall( - address _spender, - uint _addedValue, - bytes _data - ) - public - payable - returns (bool) - { - require(_spender != address(this)); - - super.increaseApproval(_spender, _addedValue); - - // solium-disable-next-line security/no-call-value - require(_spender.call.value(msg.value)(_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 decreaseApprovalAndCall( - address _spender, - uint _subtractedValue, - bytes _data - ) - public - payable - returns (bool) - { - require(_spender != address(this)); - - super.decreaseApproval(_spender, _subtractedValue); - - // solium-disable-next-line security/no-call-value - require(_spender.call.value(msg.value)(_data)); - - return true; - } - -} diff --git a/test/token/ERC827/ERC827Token.js b/test/token/ERC827/ERC827Token.js deleted file mode 100644 index 3cfed9683..000000000 --- a/test/token/ERC827/ERC827Token.js +++ /dev/null @@ -1,489 +0,0 @@ - -import EVMRevert from '../../helpers/EVMRevert'; -var Message = artifacts.require('MessageHelper'); -var ERC827TokenMock = artifacts.require('ERC827TokenMock'); - -var BigNumber = web3.BigNumber; -require('chai') - .use(require('chai-as-promised')) - .use(require('chai-bignumber')(BigNumber)) - .should(); - -contract('ERC827 Token', function (accounts) { - let token; - - beforeEach(async function () { - token = await ERC827TokenMock.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 ERC827TokenMock.new(accounts[0], 100); - 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 () { - await token.transfer(accounts[1], 101).should.be.rejectedWith(EVMRevert); - }); - - 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); - 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 () { - let balance0 = await token.balanceOf(accounts[0]); - await token.approve(accounts[1], 99); - await token.transferFrom( - accounts[0], accounts[2], balance0 + 1, - { from: accounts[1] } - ).should.be.rejectedWith(EVMRevert); - }); - - 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 () { - await token.transfer(0x0, 100).should.be.rejectedWith(EVMRevert); - }); - - it('should throw an error when trying to transferFrom to 0x0', async function () { - await token.approve(accounts[1], 100); - await token.transferFrom(accounts[0], 0x0, 100, { from: accounts[1] }) - .should.be.rejectedWith(EVMRevert); - }); - - describe('Test ERC827 methods', function () { - it( - 'should allow payment through transfer' - , async function () { - const message = await Message.new(); - - const extraData = message.contract.buyMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - const transaction = await token.transferAndCall( - message.contract.address, 100, extraData, { from: accounts[0], value: 1000 } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(100).should.be.bignumber.equal( - await token.balanceOf(message.contract.address) - ); - new BigNumber(1000).should.be.bignumber.equal( - await web3.eth.getBalance(message.contract.address) - ); - }); - - it( - 'should allow payment through approve' - , async function () { - const message = await Message.new(); - - const extraData = message.contract.buyMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - const transaction = await token.approveAndCall( - message.contract.address, 100, extraData, { from: accounts[0], value: 1000 } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(100).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - new BigNumber(1000).should.be.bignumber.equal( - await web3.eth.getBalance(message.contract.address) - ); - }); - - it( - 'should allow payment through increaseApproval' - , async function () { - const message = await Message.new(); - - const extraData = message.contract.buyMessage.getData( - 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 transaction = await token.increaseApprovalAndCall( - message.contract.address, 50, extraData, { from: accounts[0], value: 1000 } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(60).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - new BigNumber(1000).should.be.bignumber.equal( - await web3.eth.getBalance(message.contract.address) - ); - }); - - it( - 'should allow payment through decreaseApproval' - , async function () { - const message = await Message.new(); - - 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.buyMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - const transaction = await token.decreaseApprovalAndCall( - message.contract.address, 60, extraData, { from: accounts[0], value: 1000 } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(40).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - new BigNumber(1000).should.be.bignumber.equal( - await web3.eth.getBalance(message.contract.address) - ); - }); - - it( - 'should allow payment through transferFrom' - , async function () { - const message = await Message.new(); - - const extraData = message.contract.buyMessage.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 transaction = await token.transferFromAndCall( - accounts[0], message.contract.address, 100, extraData, { from: accounts[1], value: 1000 } - ); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(100).should.be.bignumber.equal( - await token.balanceOf(message.contract.address) - ); - new BigNumber(1000).should.be.bignumber.equal( - await web3.eth.getBalance(message.contract.address) - ); - }); - - it('should revert funds of failure inside approve (with data)', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.approveAndCall( - message.contract.address, 10, extraData, { from: accounts[0], value: 1000 } - ).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)); - new BigNumber(0).should.be.bignumber - .equal(await web3.eth.getBalance(message.contract.address)); - }); - - it('should revert funds of failure inside transfer (with data)', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.transferAndCall( - message.contract.address, 10, extraData, { from: accounts[0], value: 1000 } - ).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)); - new BigNumber(0).should.be.bignumber - .equal(await web3.eth.getBalance(message.contract.address)); - }); - - it('should revert funds of failure inside transferFrom (with data)', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.approve(accounts[1], 10, { from: accounts[2] }); - - await token.transferFromAndCall( - accounts[2], message.contract.address, 10, extraData, { from: accounts[2], value: 1000 } - ).should.be.rejectedWith(EVMRevert); - - // 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)); - new BigNumber(0).should.be.bignumber - .equal(await web3.eth.getBalance(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 transaction = await token.transferAndCall(message.contract.address, 100, extraData); - - 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 transaction = await token.approveAndCall(message.contract.address, 100, extraData); - - 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 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' - ); - - await token.approve(message.contract.address, 10); - new BigNumber(10).should.be.bignumber.equal( - await token.allowance(accounts[0], message.contract.address) - ); - - const transaction = await token.increaseApprovalAndCall(message.contract.address, 50, extraData); - - assert.equal(2, transaction.receipt.logs.length); - - new BigNumber(60).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); - - 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' - ); - - const transaction = await token.decreaseApprovalAndCall(message.contract.address, 60, extraData); - - 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 () { - 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 transaction = await token.transferFromAndCall(accounts[0], message.contract.address, 100, extraData, { - 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 approve (with data)', async function () { - const message = await Message.new(); - - const extraData = message.contract.fail.getData(); - - await token.approveAndCall(message.contract.address, 10, extraData) - .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 transfer (with data)', async function () { - const message = await Message.new(); - - const extraData = message.contract.fail.getData(); - - await token.transferAndCall(message.contract.address, 10, extraData) - .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 transferFrom (with data)', async function () { - const message = await Message.new(); - - const extraData = message.contract.fail.getData(); - - await token.approve(accounts[1], 10, { from: accounts[2] }); - await token.transferFromAndCall(accounts[2], message.contract.address, 10, extraData, { from: accounts[1] }) - .should.be.rejectedWith(EVMRevert); - - // 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)); - }); - - it('should fail approve (with data) when using token contract address as receiver', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.approveAndCall(token.contract.address, 100, extraData, { from: accounts[0] }) - .should.be.rejectedWith(EVMRevert); - }); - - it('should fail transfer (with data) when using token contract address as receiver', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.transferAndCall(token.contract.address, 100, extraData) - .should.be.rejectedWith(EVMRevert); - }); - - it('should fail transferFrom (with data) when using token contract address as receiver', async function () { - const message = await Message.new(); - - const extraData = message.contract.showMessage.getData( - web3.toHex(123456), 666, 'Transfer Done' - ); - - await token.approve(accounts[1], 1, { from: accounts[0] }); - - await token.transferFromAndCall(accounts[0], token.contract.address, 1, extraData, { from: accounts[1] }) - .should.be.rejectedWith(EVMRevert); - }); - }); -});