Calling renounceMinter() at the finalization of FinalizableCrowdsale

I’m trying to renounce the crowdsale contract’s minter rights after the crowdsale is finalized. However, the MinterRole interface clashes from the one from MintedCrowdsale.sol (Identifier already declared).

How should I go about calling the renounceMinter() function of the token from the crowdsale contract? Here’s what I have:

pragma solidity 0.5.2;

import '../node_modules/openzeppelin-solidity/contracts/crowdsale/Crowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/validation/TimedCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/validation/CappedCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/distribution/FinalizableCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol';

interface MinterRole {
    function renounceMinter() public;
}

contract TestCrowdsale is Crowdsale, TimedCrowdsale, CappedCrowdsale, MintedCrowdsale, FinalizableCrowdsale {
    constructor(uint256 _rate, address payable _wallet, ERC20 _token, uint256 _openingTime, uint256 _closingTime, uint256 _cap)
        Crowdsale(_rate, _wallet, _token)
        TimedCrowdsale(_openingTime, _closingTime)
        CappedCrowdsale(_cap)
        public
        {

        }

        function finalization() internal {
            MinterRole(token).renounceMinter();
            super._finalization();
        }
}

Hi @pepelek welcome to the community. I’m tagging @frangio to attend to your issue. Meanwhile please do say hi at our introduction thread here.
https://forum.openzeppelin.com/t/introduce-yourself-here/88/108

Welcome @pepelek!

Let’s look at the error message and see what it tells us.

TestCrowdsale.sol:10:1: DeclarationError: Identifier already declared.
interface MinterRole {
^ (Relevant source part starts here and spans across multiple lines).
TestCrowdsale.sol:6:1: The previous declaration is here:
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol';
^----------------------------------------------------------------------------------------------^

The first line says that there’s an identifier being declared twice. The second and third lines say that this identifier is MinterRole. The rest of the error message says that the previous declaration is in the file MintedCrowdsale.sol of OpenZeppelin.

What we should interpret here is that importing MintedCrowdsale.sol already brings MinterRole into scope for you. I know this is confusing because you would think you’re only importing MintedCrowdsale, but because of the way Solidity works, since MintedCrowdsale uses the MinterRole interface, it is also being imported.

This means that you can delete your custom declaration of the MinterRole interface and things should compile and work fine.

Hey @frangio , thanks for the reply! Without the interface, it throws Explicit type conversion not allowed from "function () view returns (contract IERC20)" to "contract MinterRole".

Anyway, here’s what worked for me (suggested by thodges-gh at solidity gitter)

pragma solidity 0.5.2;

import '../node_modules/openzeppelin-solidity/contracts/crowdsale/Crowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/validation/TimedCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/validation/CappedCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/emission/MintedCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/crowdsale/distribution/FinalizableCrowdsale.sol';
import '../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol';

interface IMinterRole {
    function renounceMinter() external;
}

contract TestCrowdsale is Crowdsale, TimedCrowdsale, CappedCrowdsale, MintedCrowdsale, FinalizableCrowdsale {
    constructor(uint256 _rate, address payable _wallet, ERC20 _token, uint256 _openingTime, uint256 _closingTime, uint256 _cap)
        Crowdsale(_rate, _wallet, _token)
        TimedCrowdsale(_openingTime, _closingTime)
        CappedCrowdsale(_cap)
        public
        {

        }

        function finalization() internal {
            IMinterRole(address(token())).renounceMinter();
            super._finalization();
        }
}

Ah, yes I forgot to mention you also needed to add the parentheses, and then the cast. Glad it worked!