AccessManager won't let me call my function: AccessManagedUnauthorized

Hi guys!

Any idea what i am doing wrong here?

I have a Corp (is AccessManager) contract that creates a AccountDatabase (is AccessManaged) contract which has an add function to add EmployeeAccount contracts into an array.

Now the add function should be restricted to the Corp contract until setup otherwise.

While creating the Corp contract it should add a Founder (is EmployeeAccount) contract into the AccountDatabase.

But i always get a AccessManagedUnauthorized error when calling add.

To test this, i separated the logic into this test function which also reverts with an AccessManagedUnauthorized error.

function test_1_Found() public {
        vm.startPrank(ACCOUNT_ADDRESS, ACCOUNT_ADDRESS);
        Corp corp = new Corp(ACCOUNT_ADDRESS);

        bytes4[] memory addfuncs = new bytes4[](1);
        addfuncs[0] = bytes4(keccak256("add(address)"));

        // accountDatabaseAddress() returns the contract address that holds all employee contracts
        corp.setTargetFunctionRole(corp.accountDatabaseAddress(), addfuncs, 60);
        corp.grantRole(60, address(corp), 0);

        Founder founder = new Founder(ACCOUNT_ADDRESS);
        vm.stopPrank();

        vm.startPrank(address(corp), address(corp));
        corp.accounts().add(address(founder));
        vm.stopPrank();
    }

In the Event logs i see RoleGranted(roleId: 60, account: <CORP_CONTRACT_ADDRESS>, delay: 0, since: 1680220800 [1.68e9], newMember: true) aswell as TargetFunctionRoleUpdated(target: AccountDatabase: [ACCOUNT_DATABASE_ADDRESS], selector: 0x0a3b0a4f00000000000000000000000000000000000000000000000000000000, roleId: 60).

So my add call should not fail. But somehow it does, returning (false, 0).

I've come to find that AccessManager/AccessManaged would highly benefit from code examples in the docs.
Thanks for any suggestions!

1 Like

I think you issue here is that the caller is also the AccessManager. This special cases is treated in a specific way (see line 138 of AccessManager.sol)

This is not solmething the system was designed to do. The AccessManager was designed to be a standalone contract that does include additional functionnality beside permission management.

You might be able to achieve what you want by going through execute

vm.startPrank(address(corp), address(corp));
corp.execute(corp.accounts(), abi.encodeCall(AccountDatabase.add, (founder));
vm.stopPrank();

But my advice would be to separate Corp and AccessManager so they are two distinct contracts.
Also, be aware that praking a contract's address and then calling that contract may no reflect transaction workflows that will happen on real chains.

1 Like