I'm relatively new to Solidity and currently working on building a DAO using the OpenZeppelin contract wizard. I've generated ERC-20 token and governor contracts using the wizard to kickstart my project. However, I encountered an issue while setting up my unit tests. Specifically, I'm receiving an error message "AccessManagedUnauthorized" when attempting to mint tokens.
Here's how I've set up my test contract:
contract KachalGovTest is Test {
KachalCoin kcoin;
TimeLock timelock;
address public USER = makeAddr("user");
uint256 public constant INITIAL_SUPPLY = 10 ether;
function setUp() public {
vm.startPrank(USER);
kcoin = new KachalCoin(USER);
kcoin.mint(USER, INITIAL_SUPPLY);
kcoin.setAuthority(USER);
kcoin.delegate(USER);
timelock = new TimeLock(MIN_DELAY, proposers, executors);
```
I'm utilizing the Foundry framework for testing. Below is the remainder of my test contract along with the ERC-20 token implementation.
I've attempted to dive into the documentation and explore the OpenZeppelin contract code, particularly examining contracts like AccessManaged, but unfortunately, I'm still struggling to grasp the issue. Any guidance or insight on resolving this would be greatly appreciated. Thank you!
test contract:
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {KachalBox} from "../src/KachalBox.sol";
import {KachalCoin} from "../src/KachalCoin.sol";
import {KachalGov} from "../src/KachalGov.sol";
import {TimeLock} from "../src/TimeLock.sol";
contract KachalGovTest is Test {
KachalBox kbox;
KachalCoin kcoin;
KachalGov kgov;
TimeLock timelock;
address public USER = makeAddr("user");
uint256 public constant INITIAL_SUPPLY = 10 ether;
// arguments for TimeLock
uint256 public constant MIN_DELAY = 3600; // 1 hour after a vote passes
address[] proposers;
address[] executors;
function setUp() public {
vm.startPrank(USER);
kcoin = new KachalCoin(USER);
kcoin.mint(USER, INITIAL_SUPPLY);
kcoin.setAuthority(USER);
kcoin.delegate(USER);
timelock = new TimeLock(MIN_DELAY, proposers, executors);
// now we can deploy our gov contract
kgov = new KachalGov(kcoin, timelock);
// now we should give some rules
// the way that time locker has roles, it hashes the names of stuff
bytes32 proposersRole = timelock.PROPOSER_ROLE();
// there is a function in timelock name PROPOSER_ROLE, and we are going to alow this
// proposer role to be just the governer, so only the governor can propose stuff to the timelock
bytes32 executorRole = timelock.EXECUTOR_ROLE();
// any body can execute by setting it to zero address
bytes32 adminRole = timelock.DEFAULT_ADMIN_ROLE();
// time lock start with some default rolls
// and we need to grant the governor whole bunch of rolls
timelock.grantRole(proposersRole, address(kgov));
// as a grant role function, we grant the proposersRole to the governor so only the governor
// can actually propose stuff to timelock\
timelock.grantRole(executorRole, address(0));
// and we need to remove our-selves as the admin of time locker
timelock.revokeRole(adminRole, address(USER));
// so the user can no longer be the admin
vm.stopPrank();
kbox = new KachalBox();
kbox.transferOwnership(address(timelock));
}
// now we can write a quick test:
function testCantUpdateBoxWithoutGovernance() public {
vm.expectRevert();
kbox.store(1);
}
function testWhoIsTheInitialAuthority() public view {
// kcoin = new KachalCoin(USER);
assertEq(kcoin.authority(), USER, "The initial Authority should be USER address!");
}
function testUSERCanMint() public {
vm.startPrank(USER);
kcoin.mint(USER, INITIAL_SUPPLY);
vm.stopPrank();
assertEq(kcoin.balanceOf(USER), INITIAL_SUPPLY, "The USER address should have the minted tokens");
}
function testMintingPermissions() public {
vm.startPrank(USER); // Set caller as the governor
kcoin.mint(USER, 100);
vm.stopPrank();
assertEq(kcoin.balanceOf(USER), INITIAL_SUPPLY + 100, "The governor should be able to mint tokens");
}
}
ERC-20 contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {ERC20Pausable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol";
import {ERC20Permit, Nonces} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {ERC20Votes} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
contract KachalCoin is ERC20, ERC20Burnable, ERC20Pausable, AccessManaged, ERC20Permit, ERC20Votes {
constructor(address initialAuthority)
ERC20("KachalCoin", "KCH")
AccessManaged(initialAuthority)
ERC20Permit("KachalCoin")
{}
function pause() public restricted {
_pause();
}
function unpause() public restricted {
_unpause();
}
function mint(address to, uint256 amount) public restricted {
_mint(to, amount);
}
function clock() public view override returns (uint48) {
return uint48(block.timestamp);
}
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public pure override returns (string memory) {
return "mode=timestamp";
}
// The following functions are overrides required by Solidity.
function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Pausable, ERC20Votes) {
super._update(from, to, value);
}
function nonces(address owner) public view override(ERC20Permit, Nonces) returns (uint256) {
return super.nonces(owner);
}
}
here is the error massage:
[FAIL. Reason: setup failed: AccessManagedUnauthorized(0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D)] setUp() (gas: 0)
Traces:
[2021802] KachalGovTest::setUp()
├─ [0] VM::startPrank(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return]
├─ [1957628] → new KachalCoin@0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353
│ ├─ emit AuthorityUpdated(authority: user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D])
│ └─ ← [Return] 9428 bytes of code
├─ [1900] KachalCoin::mint(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], 10000000000000000000 [1e19])
│ ├─ [0] user::canCall(user: [0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D], KachalCoin: [0x7BD1119CEC127eeCDBa5DCA7d1Bd59986f6d7353], 0x40c10f1900000000000000000000000000000000000000000000000000000000) [staticcall]
│ │ └─ ← [Stop]
│ └─ ← [Revert] AccessManagedUnauthorized(0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D)
└─ ← [Revert] AccessManagedUnauthorized(0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 2.01ms (0.00ns CPU time)
Ran 1 test suite in 1.58s (2.01ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/KachalGovTest.t.sol:KachalGovTest
[FAIL. Reason: setup failed: AccessManagedUnauthorized(0x6CA6d1e2D5347Bfab1d91e883F1915560e09129D)] setUp() (gas: 0)
Encountered a total of 1 failing tests, 0 tests succeeded