Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 })); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); |