Description
In CrimeMoney
contract, only address with "moneyshelf" role can mint or burn the token, which is originally the MoneyShelf
contract, granted in Deployer.s.sol
script. But after migration, MoneyVault
is not granted as "moneyshelf" role.
Impact
After migration, MoneyVault
cannot burn CrimeMoney, so godfather cannot withdraw USDC from it.
Proof of Concept
function test_migrateAndWithdraw() public {
address alice = makeAddr("alice");
assertEq(address(kernel.getModuleForKeycode(Keycode.wrap("MONEY"))), address(moneyShelf));
joinGangGodFather();
joinGang(address(this));
vm.prank(godFather);
usdc.transfer(alice, 100e6);
vm.startPrank(alice);
usdc.approve(address(moneyShelf), 100e6);
laundrette.depositTheCrimeMoneyInATM(alice, alice, 100e6);
vm.stopPrank();
assertEq(usdc.balanceOf(alice), 0);
assertEq(usdc.balanceOf(address(moneyShelf)), 100e6);
assertEq(crimeMoney.balanceOf(alice), 100e6);
EmergencyMigration migration = new EmergencyMigration();
MoneyVault moneyVault = migration.migrate(kernel, usdc, crimeMoney, moneyShelf, laundrette);
assertEq(usdc.balanceOf(address(moneyVault)), 0);
vm.prank(godFather);
vm.expectRevert();
laundrette.withdrawMoney(alice, godFather, 100e6);
}
Recommendations
grant "moneyshelf" role to new MoneyVault
contract. But since admin role is already transferred to laundrette
, we can add a function in laundrette to grant role:
in laundrette:
++ function grantRoleMoneyShelf(address _moneyShelf) external isGodFather {
++ kernel.grantRole(Role.wrap("moneyshelf"), _moneyShelf);
++ }
in EmergencyMigration.s.sol
++ laundrette.grantRoleMoneyShelf(address(moneyVault));