Skip to content

Commit

Permalink
Merge ffe1589 into 4a10f72
Browse files Browse the repository at this point in the history
  • Loading branch information
vittominacori committed Apr 30, 2018
2 parents 4a10f72 + ffe1589 commit 62f2fb7
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
41 changes: 41 additions & 0 deletions contracts/token/ERC20/RBACMintableToken.sol
@@ -0,0 +1,41 @@
pragma solidity ^0.4.21;

import "./MintableToken.sol";
import "../../ownership/rbac/RBACWithAdmin.sol";


/**
* @title RBACMintable token
* @author Vittorio Minacori (@vittominacori)
* @dev Simple ERC20 Mintable Token, with RBAC minter permissions
*/
contract RBACMintableToken is MintableToken, RBACWithAdmin {
/**
* A constant role name for indicating minters.
*/
string public constant ROLE_MINTER = "minter";

/**
* @dev modifier to scope access to minters
* // reverts
*/
modifier onlyMinter()
{
checkRole(msg.sender, ROLE_MINTER);
_;
}

/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyMinter canMint public returns (bool) {
totalSupply_ = totalSupply_.add(_amount);
balances[_to] = balances[_to].add(_amount);
emit Mint(_to, _amount);
emit Transfer(address(0), _to, _amount);
return true;
}
}
63 changes: 63 additions & 0 deletions test/crowdsale/RBACMintedCrowdsale.test.js
@@ -0,0 +1,63 @@
import ether from '../helpers/ether';

const BigNumber = web3.BigNumber;

const should = require('chai')
.use(require('chai-as-promised'))
.use(require('chai-bignumber')(BigNumber))
.should();

const MintedCrowdsale = artifacts.require('MintedCrowdsaleImpl');
const RBACMintableToken = artifacts.require('RBACMintableToken');

const ROLE_MINTER = 'minter';

contract('MintedCrowdsale using RBACMintableToken', function ([_, investor, wallet, purchaser]) {
const rate = new BigNumber(1000);
const value = ether(5);

const expectedTokenAmount = rate.mul(value);

beforeEach(async function () {
this.token = await RBACMintableToken.new();
this.crowdsale = await MintedCrowdsale.new(rate, wallet, this.token.address);
await this.token.adminAddRole(this.crowdsale.address, ROLE_MINTER);
});

describe('accepting payments', function () {
it('should have minter role on token', async function () {
const isMinter = await this.token.hasRole(this.crowdsale.address, ROLE_MINTER);
isMinter.should.equal(true);
});

it('should accept payments', async function () {
await this.crowdsale.send(value).should.be.fulfilled;
await this.crowdsale.buyTokens(investor, { value: value, from: purchaser }).should.be.fulfilled;
});
});

describe('high-level purchase', function () {
it('should log purchase', async function () {
const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor });
const event = logs.find(e => e.event === 'TokenPurchase');
should.exist(event);
event.args.purchaser.should.equal(investor);
event.args.beneficiary.should.equal(investor);
event.args.value.should.be.bignumber.equal(value);
event.args.amount.should.be.bignumber.equal(expectedTokenAmount);
});

it('should assign tokens to sender', async function () {
await this.crowdsale.sendTransaction({ value: value, from: investor });
let balance = await this.token.balanceOf(investor);
balance.should.be.bignumber.equal(expectedTokenAmount);
});

it('should forward funds to wallet', async function () {
const pre = web3.eth.getBalance(wallet);
await this.crowdsale.sendTransaction({ value, from: investor });
const post = web3.eth.getBalance(wallet);
post.minus(pre).should.be.bignumber.equal(value);
});
});
});
68 changes: 68 additions & 0 deletions test/token/ERC20/RBACMintableToken.test.js
@@ -0,0 +1,68 @@
import assertRevert from '../../helpers/assertRevert';
const RBACMintableToken = artifacts.require('RBACMintableToken');

const ROLE_MINTER = 'minter';

contract('RBACMintable', function ([owner, anotherAccount, minter]) {
beforeEach(async function () {
this.token = await RBACMintableToken.new({ from: owner });
await this.token.adminAddRole(minter, ROLE_MINTER);
});

describe('mint', function () {
const amount = 100;

describe('when the sender has the minter role', function () {
const from = minter;

describe('when the token minting is not finished', function () {
it('mints the requested amount', async function () {
await this.token.mint(owner, amount, { from });

const balance = await this.token.balanceOf(owner);
assert.equal(balance, amount);
});

it('emits a mint and a transfer event', async function () {
const { logs } = await this.token.mint(owner, amount, { from });

assert.equal(logs.length, 2);
assert.equal(logs[0].event, 'Mint');
assert.equal(logs[0].args.to, owner);
assert.equal(logs[0].args.amount, amount);
assert.equal(logs[1].event, 'Transfer');
});
});

describe('when the token minting is finished', function () {
beforeEach(async function () {
await this.token.finishMinting({ from: owner });
});

it('reverts', async function () {
await assertRevert(this.token.mint(owner, amount, { from }));
});
});
});

describe('when the sender has not the minter role', function () {
const from = anotherAccount;

describe('when the token minting is not finished', function () {
it('reverts', async function () {
await assertRevert(this.token.mint(owner, amount, { from }));
});
});

describe('when the token minting is already finished', function () {
beforeEach(async function () {
await this.token.finishMinting({ from: owner });
});

it('reverts', async function () {
await assertRevert(this.token.mint(owner, amount, { from }));
});
});
});
});
});

0 comments on commit 62f2fb7

Please sign in to comment.