From ca10d73a18553e18bd141a57457d0934ad9aa83a Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Tue, 19 May 2020 13:08:11 +0300 Subject: [PATCH 1/4] firstr version --- contracts/misc/CommonToken.sol | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 contracts/misc/CommonToken.sol diff --git a/contracts/misc/CommonToken.sol b/contracts/misc/CommonToken.sol new file mode 100644 index 00000000..033b5ac9 --- /dev/null +++ b/contracts/misc/CommonToken.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.5.17; + +import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/StandaloneERC20.sol"; +import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.sol"; + + +/** + * @title CommonToken, base on zeppelin contract. + * @dev ERC20 compatible token. It is a mintable, burnable token(onlyOwner) + */ +contract CommonToken is StandaloneERC20 { + + /** + * @dev Destroys `amount` tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 amount) public onlyMinter { + _burn(_msgSender(), amount); + } +} From 0745e59fda8a24e9f917ef127392c07c07d8c6e0 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Tue, 19 May 2020 13:18:42 +0300 Subject: [PATCH 2/4] fix --- contracts/misc/CommonToken.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/misc/CommonToken.sol b/contracts/misc/CommonToken.sol index 033b5ac9..af079e1f 100644 --- a/contracts/misc/CommonToken.sol +++ b/contracts/misc/CommonToken.sol @@ -15,7 +15,7 @@ contract CommonToken is StandaloneERC20 { * * See {ERC20-_burn}. */ - function burn(uint256 amount) public onlyMinter { - _burn(_msgSender(), amount); + function burn(address _account, uint256 _amount) public onlyMinter { + _burn(_account, _amount); } } From 508c13202915991f1fefb7ba69784818de3d2095 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Wed, 20 May 2020 12:06:59 +0300 Subject: [PATCH 3/4] tests --- contracts/misc/CommonToken.sol | 2 +- test/commontoken.js | 170 +++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 test/commontoken.js diff --git a/contracts/misc/CommonToken.sol b/contracts/misc/CommonToken.sol index af079e1f..d9acb353 100644 --- a/contracts/misc/CommonToken.sol +++ b/contracts/misc/CommonToken.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC20/IERC20.so /** * @title CommonToken, base on zeppelin contract. - * @dev ERC20 compatible token. It is a mintable, burnable token(onlyOwner) + * @dev ERC20 compatible token. It is a mintable, burnable token(onlyMinter) */ contract CommonToken is StandaloneERC20 { diff --git a/test/commontoken.js b/test/commontoken.js new file mode 100644 index 00000000..6ba1498e --- /dev/null +++ b/test/commontoken.js @@ -0,0 +1,170 @@ +const helpers = require('./helpers'); + +const CommonToken = artifacts.require("./CommonToken.sol"); +var token; +contract('CommonToken', accounts => { + const testTokenName = "CommonToken"; + const testTokenSymbol = "CMN"; + beforeEach( async function() { + token = await CommonToken.new(); + await token.initialize(testTokenName,testTokenSymbol,18,[accounts[0]],[accounts[0]]); + }); + it("should put 0 Coins in the first account", async () => { + + let balance = await token.balanceOf.call(accounts[0]); + assert.equal(balance.valueOf(), 0); + }); + + it("should be owned by its creator", async () => { + + assert.equal(await token.isMinter(accounts[0]), true); + }); + + it("should mint tokens to owner account", async () => { + await helpers.etherForEveryone(accounts); + + let owner, totalSupply, userSupply; + + totalSupply = await token.totalSupply(); + owner = accounts[0]; + userSupply = await token.balanceOf(owner); + assert.equal(totalSupply, 0); + assert.equal(userSupply, 0); + + await token.mint(owner, 1000); + totalSupply = await token.totalSupply(); + userSupply = await token.balanceOf(owner); + assert.equal(totalSupply, 1000); + assert.equal(userSupply, 1000); + + await token.mint(accounts[2], 1300); + totalSupply = await token.totalSupply(); + userSupply = await token.balanceOf(accounts[2]); + assert.equal(totalSupply, 2300); + assert.equal(userSupply, 1300); + + }); + + it("should allow minting tokens only by owner", async () => { + await helpers.etherForEveryone(accounts); + + let owner = accounts[0]; + let totalSupply = await token.totalSupply(); + + // calling 'mint' as a non-owner throws an error + try { + await token.mint(owner, 1000, { 'from': accounts[1] }); + throw 'an error'; + } catch (error) { + helpers.assertVMException(error); + } + + // and so the supply of tokens should remain unchanged + let newSupply = await token.totalSupply(); + assert.equal(totalSupply.toNumber(), newSupply.toNumber()); + }); + + it("log the Transfer event on mint", async () => { + + + const tx = await token.mint(accounts[1], 1000, { from: accounts[0] }); + + assert.equal(tx.logs.length, 1); + assert.equal(tx.logs[0].event, "Transfer"); + assert.equal(tx.logs[0].args.to, accounts[1]); + assert.equal(tx.logs[0].args.value.toNumber(), 1000); + }); + + it("mint should be reflected in totalSupply", async () => { + + + await token.mint(accounts[1], 1000, { from: accounts[0] }); + let amount = await token.totalSupply(); + + assert.equal(amount, 1000); + + await token.mint(accounts[2], 500, { from: accounts[0] }); + amount = await token.totalSupply(); + + assert.equal(amount.toNumber(), 1500); + }); + + it("mint should be reflected in balances", async () => { + + + await token.mint(accounts[1], 1000, { from: accounts[0] }); + + const amount = await token.balanceOf(accounts[1]); + + assert.equal(amount.toNumber(), 1000); + }); + + it("totalSupply is 0 on init", async () => { + + + const totalSupply = await token.totalSupply(); + + assert.equal(totalSupply.toNumber(), 0); + }); + + it("burn", async () => { + + await token.mint(accounts[1], 1000, { from: accounts[0] }); + + var amount = await token.balanceOf(accounts[1]); + + assert.equal(amount.toNumber(), 1000); + + await token.burn(accounts[1] ,100); + + amount = await token.balanceOf(accounts[1]); + + assert.equal(amount.toNumber(), 900); + + const totalSupply = await token.totalSupply(); + + assert.equal(totalSupply.toNumber(), 900); + }); + + + describe('onlyOwner', () => { + it('mint by owner', async () => { + try { + await token.mint(accounts[1], 10, { from: accounts[0] }); + } catch (ex) { + assert(false, 'owner could not mint'); + } + }); + + it('mint by not owner', async () => { + + try { + await token.mint(accounts[1], 10, { from: accounts[1] }); + } catch (ex) { + return; + } + + assert(false, 'non-owner was able to mint'); + }); + + it('burn by owner', async () => { + await token.mint(accounts[1], 10); + try { + await token.burn(accounts[1], 10, { from: accounts[0] }); + } catch (ex) { + assert(false, 'owner could not mint'); + } + }); + + it('burn by not owner', async () => { + await token.mint(accounts[1], 10, { from: accounts[0] }); + try { + await token.burn(accounts[1], 10, { from: accounts[1] }); + } catch (ex) { + return; + } + + assert(false, 'non-owner was able to mint'); + }); + }); +}); From 54f98db29f51ad7b5bc07628fbdb03ff84b7a8c2 Mon Sep 17 00:00:00 2001 From: Oren Sokolowsky Date: Wed, 20 May 2020 17:41:29 +0300 Subject: [PATCH 4/4] split long controller tests --- test/controller.js | 71 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/test/controller.js b/test/controller.js index 2c814d20..b4dda234 100644 --- a/test/controller.js +++ b/test/controller.js @@ -105,11 +105,37 @@ contract('Controller', accounts => { assert.equal(tx.logs[0].event, "RegisterScheme"); }); - it("register schemes - check permissions for register new scheme", async () => { + it("register schemes - check permissions for register new scheme 0-7", async () => { // Check scheme has at least the permissions it is changing, and at least the current permissions. var i,j; // controller; - for(j = 0; j <= 15; j++ ){ + for(j = 0; j <= 7; j++ ){ + //registered scheme has already permission to register(2) + controller = await setup(accounts,'0x'+uint32.toHex(j|2)); + var register; + for(i = 0; i <= 15; i++ ){ + register = true; + try { + await controller.registerScheme(accounts[1],'0x'+uint32.toHex(i)); + } catch (ex) { + //registered scheme has already permission to register(2) and is register(1). + assert.notEqual(i&(~(j|3),0)); + register = false; + } + if (register){ + await controller.unregisterScheme(accounts[1]); + register= false; + } + } + } + }); + + + it("register schemes - check permissions for register new scheme 7-15", async () => { + // Check scheme has at least the permissions it is changing, and at least the current permissions. + var i,j; + // controller; + for(j = 7; j <= 15; j++ ){ //registered scheme has already permission to register(2) controller = await setup(accounts,'0x'+uint32.toHex(j|2)); var register; @@ -158,7 +184,7 @@ contract('Controller', accounts => { assert.equal(tx.logs.length, 0); }); - it("unregister schemes - check permissions unregister scheme", async () => { + it("unregister schemes - check permissions unregister scheme 0-7", async () => { // Check scheme has at least the permissions it is changing, and at least the current permissions. //1. setup controller = await setup(accounts); @@ -167,7 +193,7 @@ contract('Controller', accounts => { var tx; var registeredScheme = accounts[1]; var unregisteredScheme = accounts[2]; - for(i = 0; i <= 15; i++ ){ + for(i = 0; i <= 7; i++ ){ //registered scheme has already permission to register(2) tx = await controller.registerScheme(registeredScheme,'0x'+uint32.toHex(i|3)); assert.equal(tx.logs.length, 1); @@ -195,6 +221,43 @@ contract('Controller', accounts => { } }); + it("unregister schemes - check permissions unregister scheme 7-15", async () => { + // Check scheme has at least the permissions it is changing, and at least the current permissions. + //1. setup + controller = await setup(accounts); + //2. account[0] register schemes ,on account[1] with variables permissions which could unregister other schemes. + var i,j; + var tx; + var registeredScheme = accounts[1]; + var unregisteredScheme = accounts[2]; + for(i = 7; i <= 15; i++ ){ + //registered scheme has already permission to register(2) + tx = await controller.registerScheme(registeredScheme,'0x'+uint32.toHex(i|3)); + assert.equal(tx.logs.length, 1); + assert.equal(tx.logs[0].event, "RegisterScheme"); + for(j = 0; j <= 15; j++ ){ + tx = await controller.registerScheme(unregisteredScheme,'0x'+uint32.toHex(j)); + assert.equal(tx.logs.length, 1); + assert.equal(tx.logs[0].event, "RegisterScheme"); + //try to unregisterScheme + if (j&(~(i|3))) { + //unregister should fail + try { + await controller.unregisterScheme(unregisteredScheme,{ from: registeredScheme }); + assert(false, "scheme with permission " +uint32.toHex(i|3)+ " should not be able to unregister scheme with permission"+uint32.toHex(j)); + } catch (ex) { + helpers.assertVMException(ex); + } + }else{ + //unregister should succeed + tx = await controller.unregisterScheme(unregisteredScheme,{ from: registeredScheme }); + assert.equal(tx.logs.length, 1); + assert.equal(tx.logs[0].event, "UnregisterScheme"); + } + } + } + }); + it("unregister self", async () => { var tx; controller = await setup(accounts,"0x00000000");