# AccessControlUpgradeable "account x is missing role y" but x is the contract address

**URL:** <https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681>\
**Category:** Contracts\
**Created:** [March 5, 2022, 7:51am UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681 "2022-03-05T07:51:49Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![SaulMoonves](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/saulmoonves/32/13673_2.png) [@SaulMoonves](https://forum.openzeppelin.com/u/SaulMoonves)\
**Post date:** [March 5, 2022, 7:51am UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681/1 "2022-03-05T07:51:49Z")

</div>

I've deployed a transparent proxy upgradeable contract ERC721 token that uses AccessControlUpgradeable. In my initializer I use \_configRole(MINTER\_ROLE, x) to set another contract 2 ("STOREFRONT") as a valid minter. However, when I use STOREFRONT to call the minting function on my token, it reverts:

AccessControl: account 0x2c277145fa6098a9b355bfc610d7833f5453b7d8 is missing role 0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6

where 0x2c277145fa6098a9b355bfc610d7833f5453b7d8 is my proxy contract for my token on the rinkeby network and 0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6 is my MINTER\_ROLE.

I am guessing this has something to do with the upgradeable contract malfunctioning but I don't know how to proceed on this.

here is my deploy main snippet:

```auto
    const [deployer] = await ethers.getSigners();

    const AftersTokenLib = await ethers.getContractFactory("AftersTokenLib");
    const aftersTokenLib = await AftersTokenLib.deploy();
    await aftersTokenLib.deployed();

    const TokenStorage = await ethers.getContractFactory("AftersTokenStorage");
    const tokenStorage = await upgrades.deployProxy(TokenStorage, []);
    await tokenStorage.deployed();
    console.log(`Storage address: ${tokenStorage.address}`);

    const Storefront = await ethers.getContractFactory("AftersStorefront");
    const storefront = await upgrades.deployProxy(Storefront, [[deployer.address], [1], deployer.address]);
    await storefront.deployed();
    console.log(`Storefront address: ${storefront.address}`);

    const Token = await ethers.getContractFactory("AftersToken");
    const token = await upgrades.deployProxy(Token, [tokenStorage.address, storefront.address]);
    await token.deployed();
    console.log(`Token address: ${token.address}`);

    await storefront.setToken(token.address, tokenStorage.address);

```

And here is my topmost contract for the ERC721 token:

```auto
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "./IAftersTokenStorage.sol";
import "./AftersTokenBase.sol";
import "./AftersStorefront.sol";

contract AftersToken is AftersTokenBase {
    /**
        Give the minter flexibility to mint into any period even if it's not
        a current one.
     */
    function safeMint(
        uint16 periodId,
        uint8 tokenTypeId,
        bool isPresale,
        address to,
        uint16 quantity,
        string memory imageCIDOverride
    ) public onlyRole(MINTER_ROLE) whenNotPaused {
        require(quantity > 0, "QUANTITY_ZERO");
        require(to != address(0), "NONZERO_TO");

        for (uint16 i = 0; i < quantity; i++) {
            uint256 lastCount = isPresale
                ? _storage.incrementPresaleCount(periodId, tokenTypeId)
                : _storage.incrementSaleCount(periodId, tokenTypeId);

            uint256 tokenId = AftersTokenLib.nextTokenId(
                periodId,
                tokenTypeId,
                isPresale,
                lastCount
            );

            _safeMint(to, tokenId);
            if (bytes(imageCIDOverride).length > 0) {
                _storage.addTokenCIDOverride(tokenId, imageCIDOverride);
            }
        }
    }

    function initialize(IAftersTokenStorage _storage, address storefront)
        public
        initializer
    {
        __AftersTokenBase_init(_storage, storefront);
    }
}

```

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [March 9, 2022, 10:02pm UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681/2 "2022-03-09T22:02:08Z")

</div>

Would you be able to share the code for AftersTokenBase? I don't see where you're granting the minter role.

---

<div class="post-metadata">

**Author:** ![SaulMoonves](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/saulmoonves/32/13673_2.png) [@SaulMoonves](https://forum.openzeppelin.com/u/SaulMoonves)\
**Post date:** [March 11, 2022, 5:53pm UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681/3 "2022-03-11T17:53:13Z")

</div>

Sure, here it is:

```auto
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.11;

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
import "./IAftersTokenStorage.sol";
import "./AftersTokenLib.sol";

/**
    Putting all the non-standard and utility stuff in here.
 */
contract AftersTokenBase is
    AccessControlUpgradeable,
    PausableUpgradeable,
    ERC721Upgradeable,
    ERC721BurnableUpgradeable
{
    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    IAftersTokenStorage public _storage;

    function pause() public onlyRole(PAUSER_ROLE) {
        _pause();
    }

    function unpause() public onlyRole(PAUSER_ROLE) {
        _unpause();
    }

    function addMinter(address minter_) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _grantRole(MINTER_ROLE, minter_);
    }

    function removeMinter(address minter_) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _revokeRole(MINTER_ROLE, minter_);
    }

    function tokenExpired(uint256 tokenId) public view returns (bool) {
        require(_exists(tokenId), "token does not exist");
        IAftersTokenStorage.Period memory p = _storage.getPeriod(
            AftersTokenLib.getTokenPeriod(tokenId)
        );
        return
            !AftersTokenLib.pointBetween(
                uint64(block.timestamp),
                p.start,
                p.end
            );
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721Upgradeable)
        returns (string memory)
    {
        require(_exists(tokenId), "token does not exist");
        IAftersTokenStorage.TokenType memory _tokenType = _storage.getTokenType(
            AftersTokenLib.getTokenTypeId(tokenId)
        );
        string memory imageOverride = _storage.getTokenCIDOverride(tokenId);
        string memory imageCID = bytes(imageOverride).length == 0
            ? _tokenType.imageCID
            : imageOverride;

        IAftersTokenStorage.Period memory period = _storage.getPeriod(
            AftersTokenLib.getTokenPeriod(tokenId)
        );

        return
            AftersTokenLib.tokenDataUri(
                _tokenType.name,
                _tokenType.description,
                imageCID,
                tokenId,
                period.start,
                period.end
            );
    }

    // FIXME: add all needed interfaces
    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721Upgradeable, AccessControlUpgradeable)
        returns (bool)
    {
        return
            ERC721Upgradeable.supportsInterface(interfaceId) ||
            AccessControlUpgradeable.supportsInterface(interfaceId);
    }

    function __AftersTokenBase_init(
        IAftersTokenStorage storage_,
        address storefrontAddress
    ) public initializer {
        __AccessControl_init();
        __ERC721_init("AftersXyzToken", "AFTERS");
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(PAUSER_ROLE, _msgSender());
        _setupRole(MINTER_ROLE, storefrontAddress);
        _storage = storage_;
    }
}

```

---

<div class="post-metadata">

**Author:** ![frangio](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/frangio/32/15251_2.png) [@frangio](https://forum.openzeppelin.com/u/frangio)\
**Post date:** [March 14, 2022, 10:57pm UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681/4 "2022-03-14T22:57:08Z")

</div>

I'm not sure why it would fail. For debugging, you should call the function `hasRole` to check if your account has the minter role or not.

---

<div class="post-metadata">

**Author:** ![SaulMoonves](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/saulmoonves/32/13673_2.png) [@SaulMoonves](https://forum.openzeppelin.com/u/SaulMoonves)\
**Post date:** [March 15, 2022, 1:05am UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681/5 "2022-03-15T01:05:12Z")

</div>

OK I'll give it a shot, but it's pretty weird that it's giving the proxy contract address where msgSender should be.

---

<div class="post-metadata">

**Author:** ![pannfred](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.openzeppelin.com/pannfred/32/14912_2.png) [@pannfred](https://forum.openzeppelin.com/u/pannfred)\
**Post date:** [May 15, 2022, 2:31pm UTC](https://forum.openzeppelin.com/t/accesscontrolupgradeable-account-x-is-missing-role-y-but-x-is-the-contract-address/25681/6 "2022-05-15T14:31:28Z")

</div>

having the same issue! Any update ?
