diff --git a/apps/token/contracts/Token.sol b/apps/token/contracts/Token.sol index 3fe68a4..06810e4 100644 --- a/apps/token/contracts/Token.sol +++ b/apps/token/contracts/Token.sol @@ -21,6 +21,8 @@ contract Token is ERC20Token, AragonApp { } function mintFor(address contributorAccount, uint256 amount, uint32 contributionId) public isInitialized auth(MINT_TOKEN_ROLE) { + require(amount > 0, "INVALID_AMOUNT"); + uint256 amountInWei = amount.mul(1 ether); _mint(contributorAccount, amountInWei); emit LogMint(contributorAccount, amount, contributionId); diff --git a/apps/token/contracts/test/Spoof.sol b/apps/token/contracts/test/Spoof.sol new file mode 100644 index 0000000..34fb889 --- /dev/null +++ b/apps/token/contracts/test/Spoof.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.4.24; + +import "@aragon/os/contracts/acl/ACL.sol"; +import "@aragon/os/contracts/kernel/Kernel.sol"; +import "@aragon/os/contracts/factory/DAOFactory.sol"; + +// You might think this file is a bit odd, but let me explain. +// We only use for now those imported contracts in our tests, which +// means Truffle will not compile them for us, because they are from +// an external dependency. + + +// solium-disable-next-line no-empty-blocks +contract Spoof { + // ... +} diff --git a/apps/token/test/app.js b/apps/token/test/app.js deleted file mode 100644 index 2f583dd..0000000 --- a/apps/token/test/app.js +++ /dev/null @@ -1,5 +0,0 @@ -// const Token = artifacts.require('Token.sol'); - -contract('Token', (_accounts) => { - it('should be tested'); -}); diff --git a/apps/token/test/token.js b/apps/token/test/token.js new file mode 100644 index 0000000..b1db44f --- /dev/null +++ b/apps/token/test/token.js @@ -0,0 +1,123 @@ +const namehash = require('ethers').utils.namehash; + +// eslint-disable-next-line no-undef +const Token = artifacts.require("Token.sol"); + +// eslint-disable-next-line no-undef +const getContract = name => artifacts.require(name); +const { assertRevert } = require('@aragon/test-helpers/assertThrow'); + +const ZERO_ADDR = '0x0000000000000000000000000000000000000000'; + +contract('Token app', (accounts) => { + let kernelBase, aclBase, daoFactory, dao, r, acl, token; + + const root = accounts[0]; + const member1 = accounts[1]; + + // eslint-disable-next-line no-undef + before(async () => { + kernelBase = await getContract('Kernel').new(true); // petrify immediately + aclBase = await getContract('ACL').new(); + daoFactory = await getContract('DAOFactory').new(kernelBase.address, aclBase.address, ZERO_ADDR); + r = await daoFactory.newDAO(root); + dao = getContract('Kernel').at(r.logs.filter(l => l.event == 'DeployDAO')[0].args.dao); + acl = getContract('ACL').at(await dao.acl()); + + //create dao mamnager permission for coin owner + await acl.createPermission( + root, + dao.address, + await dao.APP_MANAGER_ROLE(), + root, + { from: root } + ); + + //get new app instance from DAO + const receipt = await dao.newAppInstance( + '0x1234', + (await Token.new()).address, + 0x0, + false, + { from: root } + ); + token = Token.at( + receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy + ); + + //apps id + let appsId = []; + appsId[0] = namehash("kredits-contribution"); + appsId[1] = namehash("kredits-contributor"); + appsId[2] = namehash("kredits-proposal"); + appsId[3] = namehash("kredits-token"); + + //init token (app) + await token.initialize(appsId); + + //create token mint permission for coin owner + await acl.createPermission( + root, + token.address, + await token.MINT_TOKEN_ROLE(), + root, + { from: root } + ); + + }); + + describe("Owner default space permissions", async () => { + it('check owner is token issuer', async () => { + let tokenIssuerPermission = await acl.hasPermission(root, token.address, await token.MINT_TOKEN_ROLE()); + // eslint-disable-next-line no-undef + assert.equal(tokenIssuerPermission, true); + }); + }); + + describe("Token issuing", async () => { + let name = "Kredits"; + let symbol = "₭S"; + let decimals = 18; + + it("check token properties", async () => { + assert.equal(await token.name(), name); // eslint-disable-line no-undef + assert.equal(await token.symbol(), symbol); // eslint-disable-line no-undef + assert.equal(await token.decimals(), decimals); // eslint-disable-line no-undef + }); + + }); + + describe("Token minting", async () => { + let tokenToMint = 250; + let ether = 1000000000000000000; + + it("should revert when mint tokens from an address that does not have minting permission", async () => { + return assertRevert(async () => { + await token.mintFor(root, tokenToMint, 1, { from: member1}); + 'address does not have permission to mint tokens'; + }); + }); + + it("should revert when mint tokens to address(0)", async () => { + return assertRevert(async () => { + await token.mintFor(ZERO_ADDR, tokenToMint, 1, { from: root}); + 'invalid contributor address'; + }); + }); + + it("should revert when mint amount of tokens equal to 0", async () => { + return assertRevert(async () => { + await token.mintFor(root, 0, 1, { from: root}); + 'amount to mint should be greater than zero'; + }); + }); + + it("mint tokens", async () => { + await token.mintFor(root, tokenToMint, 1, { from: root }); + let ownerBalance = await token.balanceOf(root); + let totalSupply = await token.totalSupply(); + assert.equal(ownerBalance.toNumber(), tokenToMint*ether); // eslint-disable-line no-undef + assert.equal(totalSupply.toNumber(), tokenToMint*ether); // eslint-disable-line no-undef + }); + }); +});