grantRole(A_ROLE, SOMEONE) is returning missing role 0x00...000 for a function that does not use AccessControl


I am trying to write something like a whitelisting function with grantRole() to a user and then allowing that user to call a function.

function whitelistManager(address manager)
    require(!isManager[manager], "msg.sender is already a manager");
    grantRole(PENDING_MANAGER, manager);

function acceptNomination() external onlyRole(PENDING_MANAGER) {
    address potentialManager = msg.sender;
        "potentialManager is already a manager"
    isManager[potentialManager] = true;
    revokeRole(PENDING_MANAGER, potentialManager);
    grantRole(MANAGER, potentialManager);

But after calling acceptNomination(), I run into

  [101699] ContractTest::testWhitelist()
    ├─ [0] VM::prank(admin: [0x9af2e2b7e57c1cd7c68c5c3796d8ea67e0018db7])
    │   └─ ← ()
    ├─ [34221] myContract::whitelist(manager: [0x2f66c75a001ba71ccb135934f48d844b46454543])
    │   ├─ emit RoleGranted(role: 0x5d4e9d4ddf29d33dcb4adf498c491f88fe3b910c18190899deacfebbdf5e6f80, account: manager: [0x2f66c75a001ba71ccb135934f48d844b46454543], sender: admin: [0x9af2e2b7e57c1cd7c68c5c3796d8ea67e0018db7])
    │   └─ ← ()
    ├─ [652] myContract::isManager(manager: [0x2f66c75a001ba71ccb135934f48d844b46454543]) [staticcall]
    │   └─ ← false
    ├─ [0] VM::prank(manager: [0x2f66c75a001ba71ccb135934f48d844b46454543])
    │   └─ ← ()
    ├─ [52848] myContract::acceptNomination()
    │   └─ ← "AccessControl: account 0x2f66c75a001ba71ccb135934f48d844b46454543 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000"
    └─ ← "AccessControl: account 0x2f66c75a001ba71ccb135934f48d844b46454543 is missing role 0x0000000000000000000000000000000000000000000000000000000000000000"

After removing onlyRole(PENDING_MANAGER), I still run into the same error. Can someone please help me out? Thank you.

According to AccessControl documentation, by default only the role DEFAULT_ADMIN_ROLE can grant and revoke roles. So even though you grant PENDING_MANAGER to the user, that user does not have permission to revoke or grant roles in acceptNomination.

You can considering using _setRoleAdmin for more complex role relationships.

These two calls can only be executed by someone that has the administration role over PENDING_MANAGER and MANAGER, which basically require the DEFAULT_ADMIN_ROLE unless configured otherwise;

In you case you want to replace that with

    _revokeRole(PENDING_MANAGER, potentialManager);
    _grantRole(MANAGER, potentialManager);

Also, you whitelistManager is not really necessary. You could use the public grantRole function that is included in AccessControl