Hi,
I have got an issue when I try to mint an ERC20Mintable (GoodLifeToken) token via a MintedToken Sale (GLTMerchantSale).
When I am trying to execute tests implemented in Javascript I am always encountering the following error:
revert MinterRole: caller does not have the Minter role – Reason given: MinterRole: caller does not have the Minter role.
Environment
Truffle v5.0.24 (core: 5.0.24)
Solidity v0.5.0 (solc-js)
Openzeppelin v2.3.0
Details
I am assuming that the root cause is the changing msg.sender in contract ERC20Mintable:
contract ERC20Mintable is ERC20, MinterRole {
event MinterCheckedForMintable(address minterApplicant);
function mint(address account, uint256 amount) public onlyMinter returns (bool) {
emit MinterCheckedForMintable(msg.sender); //Added by myself (MarkusM)
_mint(account, amount);
return true;
}
}
Because as you can see here, msg.sender has got the address of accounts[0] (0x14fd85a2aB05Dbb2316f0C9AE283419e396BEB31) in contract GLTMerchantSale (Event TokensPurchased) and MintedCrowdsale (Event LogAddressTokenInCrowdsale):
TokensPurchased(purchaser: 0x14fd85a2aB05Dbb2316f0C9AE283419e396BEB31 (address), beneficiary: 0x7ffC5baA8Ee212d3B46906BCaeeA86Fc746076ee (address), value: 10000000000000000000 (uint256), amount: 200000 (uint256))
LogAddressTokenInCrowdsale(beneficiary: 0x7ffC5baA8Ee212d3B46906BCaeeA86Fc746076ee (address), tokenAmount: 200000 (uint256), tokenAddressInCrowdsale: 0x38eAfAe92E0Da0f3BB7f679415f312Bf4A1f5C79 (address), msgsender: 0x14fd85a2aB05Dbb2316f0C9AE283419e396BEB31 (address))
This account (accounts[0]) is registered for the MinterRole and also owns the contracts GMTMerchantSale and GoodLifeToken.
In contract ERC20Mintable “msg.sender” has suddenly changed to a completely different address:
MinterCheckedForMintable(minterApplicant: 0xd50D89cA5359d6003d95E62097A5F4cF4f75CF72 (address))
Do you have any why msg.sender has changed to this address, which belongs to a contract, that was created during the Truffle test run?
Code to reproduce
The migration Code of the ERC20Mintable-Token (GoodLifeToken) and the MintedCrowdsale (GLTMerchantSale) looks as follows:
module.exports = async function(deployer, network, accounts) {
var crowdSale;
const ethRate = new BigNumber(50000000000000); //1 EUR Cent
const wallet = accounts[0];
deployer.deploy(GoodLifeToken, { from: accounts[0] }).then(() => {
return deployer.deploy(GLTMerchantSale,
ethRate,
wallet,
GoodLifeToken.address,
{ from: accounts[0] });
}).then(inst => {
crowdSale = inst;
crowdSale.token().then(async(addr) => { tokenAddress = addr;
var goodLifeTokenInstance = await GoodLifeToken.at(tokenAddress);
goodLifeTokenInstance.addMinter(crowdSale.address)});
});
This is the implementation of the Truffle Javascript test:
let GLTMerchantSale = artifacts.require(‘GLTMerchantSale’)
let GoodLifeToken = artifacts.require(‘GoodLifeToken’)
contract(‘GLTMerchantSale’, function(accounts) {
const owner = accounts[0]
const wallet = accounts[1]
const merchant = accounts[2]
const rate = "50000000000000"
let merchantSale
beforeEach(async () => {
var crowdsale = await GLTMerchantSale.deployed({from: accounts[0]});
console.log("Crowdsale: ")
console.log(crowdsale.address)
//crowdsale.token().then(addr => { tokenAddress = addr } )
var tokenAddress = await crowdsale.token({from: accounts[0]})
console.log("Token Address: ")
console.log(tokenAddress)
merchantSale = await GLTMerchantSale.new(rate, wallet, tokenAddress, {from: accounts[0]})
})
it("should raise an amount of wei by purchachsing a given amount of EUR", async() => {
const amountInEUR = 2000
await merchantSale.buyTokens(merchant, amountInEUR, {from: accounts[0]})
var weiRaised = await merchantSale.weiRaised.call(, {from: accounts[0]})
var expected = amountInEUR * 50000000000000 * 100
assert.equal(weiRaised, expected, "WeiRaised should be 1E+19")
})
The invocation chain looks as follows:
- merchantSale.buyTokens
- MintedCrowdsale.deliverTokens
- ERC20Mintable.mint,
- MinterRole.onlyMinter, which checks if “msg.sender” is already registered as Minter. Since this not the case for the provided msg.sender the test runs finally into the error as depicted above („… caller does not have the Minter role…“)
Definition of GLTMerchantSale:
contract GLTMerchantSale is MintedCrowdsale, Ownable, MerchantRole {
….
}
Definition of GoodLifeToken:
contract GoodLifeToken is ERC20, ERC20Detailed, ERC20Mintable, ReentrancyGuard, Ownable, CustomerRole {
…
}
Is my assumption of the root cause stated above from your point of view correct?
If so, could you please tell me, why the address of msg.sender in ERC20Mintable changed to a different one and how to fix this behavior?
Thanks a lot for your support!
Markus