Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ interface IRegistrarController {
contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, SafeHelper, ZodiacRolesHelper {
IERC20 public constant USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);

IRegistrarController public constant CURRENT_REGISTRAR =
IRegistrarController(0x253553366Da8546fC250F225fe3d25d0C782303b);
IRegistrarController public constant NEW_REGISTRAR =
IRegistrarController(0x59E16fcCd424Cc24e280Be16E11Bcd56fb0CE547);
IRegistrarController public constant OLD_REGISTRAR =
Expand All @@ -52,6 +54,7 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf
}

function _beforeProposal() public override {
assertEq(CURRENT_REGISTRAR.owner(), address(timelock), "Current registrar owner should be timelock");
assertEq(NEW_REGISTRAR.owner(), address(timelock), "New registrar owner should be timelock");
assertEq(OLD_REGISTRAR.owner(), address(timelock), "Old registrar owner should be timelock");

Expand All @@ -70,7 +73,7 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf
string memory
)
{
uint256 numTransactions = 8;
uint256 numTransactions = 10;

targets = new address[](numTransactions);
values = new uint256[](numTransactions);
Expand All @@ -79,56 +82,64 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf

address managerAddr = address(manager);

// 1) Register new registrar controller
// 1) Register current registrar controller (controller.ens.eth)
targets[0] = managerAddr;
calldatas[0] = abi.encodeWithSelector(RegistrarManager.addRegistrar.selector, address(NEW_REGISTRAR));
calldatas[0] = abi.encodeWithSelector(RegistrarManager.addRegistrar.selector, address(CURRENT_REGISTRAR));

Comment on lines +85 to 88
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep generated calls consistent with draft proposal payload

_generateCallData() now includes addRegistrar(CURRENT_REGISTRAR) (and later transferOwnership for the same controller), but src/ens/proposals/ep-registrar-manager-endowment/proposalCalldata.json still defines an 8-call draft payload that does not include those operations. This means the governance simulation is validating a different transaction batch than the draft being reviewed, so the calldata check can report success while the real Tally payload remains unverified for this scope.

Useful? React with 👍 / 👎.

// 2) Register old registrar controller
// 2) Register new registrar controller
targets[1] = managerAddr;
calldatas[1] = abi.encodeWithSelector(RegistrarManager.addRegistrar.selector, address(OLD_REGISTRAR));
calldatas[1] = abi.encodeWithSelector(RegistrarManager.addRegistrar.selector, address(NEW_REGISTRAR));

// 3) Transfer ownership of new registrar to RegistrarManager
targets[2] = address(NEW_REGISTRAR);
calldatas[2] = abi.encodeWithSelector(IRegistrarController.transferOwnership.selector, managerAddr);
// 3) Register old registrar controller
targets[2] = managerAddr;
calldatas[2] = abi.encodeWithSelector(RegistrarManager.addRegistrar.selector, address(OLD_REGISTRAR));

// 4) Transfer ownership of old registrar to RegistrarManager
targets[3] = address(OLD_REGISTRAR);
// 4) Transfer ownership of current registrar to RegistrarManager
targets[3] = address(CURRENT_REGISTRAR);
calldatas[3] = abi.encodeWithSelector(IRegistrarController.transferOwnership.selector, managerAddr);

// 5) Zodiac: scope USDC target
// 5) Transfer ownership of new registrar to RegistrarManager
targets[4] = address(NEW_REGISTRAR);
calldatas[4] = abi.encodeWithSelector(IRegistrarController.transferOwnership.selector, managerAddr);

// 6) Transfer ownership of old registrar to RegistrarManager
targets[5] = address(OLD_REGISTRAR);
calldatas[5] = abi.encodeWithSelector(IRegistrarController.transferOwnership.selector, managerAddr);

// 7) Zodiac: scope USDC target
{
bytes memory inner = abi.encodeWithSelector(IRolesModifier.scopeTarget.selector, MANAGER_ROLE, address(USDC));
(targets[4], calldatas[4]) = _buildSafeExecCalldata(
(targets[6], calldatas[6]) = _buildSafeExecCalldata(
address(endowmentSafe), address(ROLES_MOD), inner, address(timelock)
);
}

// 6) Zodiac: allow USDC.transfer(timelock, amount)
// 8) Zodiac: allow USDC.transfer(timelock, amount)
{
ConditionFlat[] memory conditions = _usdcTransferConditions();
bytes memory inner = abi.encodeWithSelector(
IRolesModifier.scopeFunction.selector,
MANAGER_ROLE, address(USDC), IERC20.transfer.selector, conditions, uint8(0)
);
(targets[5], calldatas[5]) = _buildSafeExecCalldata(
(targets[7], calldatas[7]) = _buildSafeExecCalldata(
address(endowmentSafe), address(ROLES_MOD), inner, address(timelock)
);
}

// 7) Zodiac: scope timelock target
// 9) Zodiac: scope timelock target
{
bytes memory inner = abi.encodeWithSelector(IRolesModifier.scopeTarget.selector, MANAGER_ROLE, address(timelock));
(targets[6], calldatas[6]) = _buildSafeExecCalldata(
(targets[8], calldatas[8]) = _buildSafeExecCalldata(
address(endowmentSafe), address(ROLES_MOD), inner, address(timelock)
);
}

// 8) Zodiac: allow ETH sends to timelock (empty calldata, send-only)
// 10) Zodiac: allow ETH sends to timelock (empty calldata, send-only)
{
bytes memory inner = abi.encodeWithSelector(
IRolesModifier.allowFunction.selector, MANAGER_ROLE, address(timelock), bytes4(0), EXEC_SEND
);
(targets[7], calldatas[7]) = _buildSafeExecCalldata(
(targets[9], calldatas[9]) = _buildSafeExecCalldata(
address(endowmentSafe), address(ROLES_MOD), inner, address(timelock)
);
}
Expand All @@ -142,17 +153,20 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf
// RegistrarManager state
assertEq(manager.owner(), address(timelock), "RegistrarManager owner should be timelock");
assertEq(manager.destination(), address(endowmentSafe), "Destination should be endowment safe");
assertTrue(manager.isRegistrar(address(CURRENT_REGISTRAR)), "Current registrar not registered");
assertTrue(manager.isRegistrar(address(NEW_REGISTRAR)), "New registrar not registered");
assertTrue(manager.isRegistrar(address(OLD_REGISTRAR)), "Old registrar not registered");

// Ownership transferred to manager
address managerAddr = address(manager);
assertEq(CURRENT_REGISTRAR.owner(), managerAddr, "Current registrar owner should be manager");
assertEq(NEW_REGISTRAR.owner(), managerAddr, "New registrar owner should be manager");
assertEq(OLD_REGISTRAR.owner(), managerAddr, "Old registrar owner should be manager");

// WithdrawAll
uint256 balanceBefore = address(endowmentSafe).balance;
uint256 registrarBalance = address(NEW_REGISTRAR).balance + address(OLD_REGISTRAR).balance;
uint256 registrarBalance =
address(CURRENT_REGISTRAR).balance + address(NEW_REGISTRAR).balance + address(OLD_REGISTRAR).balance;
uint256 managerBalance = address(manager).balance;
manager.withdrawAll();
uint256 balanceAfter = address(endowmentSafe).balance;
Expand All @@ -163,9 +177,13 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf
"Endowment balance should increase after withdraw"
);

// Zodiac role permissions
// Zodiac role permissions — positive tests
_expectUSDCTransferAllowed();
_expectEthSendAllowed();

// Zodiac role permissions — negative tests (scoping verification)
_expectUSDCTransferToNonTimelockBlocked();
_expectEthSendToNonTimelockBlocked();
}

function _expectUSDCTransferNotAllowed() internal {
Expand Down Expand Up @@ -209,6 +227,26 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf
assertEq(balanceAfter, balanceBefore + amount, "ETH balance should increase after transfer");
}

function _expectUSDCTransferToNonTimelockBlocked() internal {
address notTimelock = address(0xdead);
uint256 amount = 1000000;

vm.startPrank(karpatkey);
bytes memory data = abi.encodeWithSelector(IERC20.transfer.selector, notTimelock, amount);
vm.expectRevert();
roles.execTransactionWithRole(address(USDC), 0, data, IZodiacRoles.Operation.Call, MANAGER_ROLE, false);
vm.stopPrank();
}

function _expectEthSendToNonTimelockBlocked() internal {
address notTimelock = address(0xdead);

vm.startPrank(karpatkey);
vm.expectRevert();
roles.execTransactionWithRole(notTimelock, 1 ether, "", IZodiacRoles.Operation.Call, MANAGER_ROLE, false);
vm.stopPrank();
}

function _usdcTransferConditions() internal view returns (ConditionFlat[] memory) {
ConditionFlat[] memory conditions = new ConditionFlat[](3);
conditions[0] = ConditionFlat({
Expand All @@ -232,6 +270,10 @@ contract Proposal_ENS_EP_Registrar_Manager_Endowment_Test is ENS_Governance, Saf
return conditions;
}

function dirPath() public pure override returns (string memory) {
return "src/ens/proposals/ep-registrar-manager-endowment";
}

function _isProposalSubmitted() public pure override returns (bool) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"proposalId": "2822069893434705582",
"type": "draft",
"executableCalls": [
{
"target": "0x62627681D92e36b9aeE1D9A6BF181373ccd42552",
"calldata": "0xaf92a693000000000000000000000000253553366da8546fc250f225fe3d25d0c782303b",
"value": "0",
"signature": ""
},
{
"target": "0x62627681D92e36b9aeE1D9A6BF181373ccd42552",
"calldata": "0xaf92a69300000000000000000000000059e16fccd424cc24e280be16e11bcd56fb0ce547",
"value": "0",
"signature": ""
},
{
"target": "0x62627681D92e36b9aeE1D9A6BF181373ccd42552",
"calldata": "0xaf92a693000000000000000000000000283af0b28c62c092c9727f1ee09c02ca627eb7f5",
"value": "0",
"signature": ""
},
{
"target": "0x253553366Da8546fC250F225fe3d25d0C782303b",
"calldata": "0xf2fde38b00000000000000000000000062627681d92e36b9aee1d9a6bf181373ccd42552",
"value": "0",
"signature": ""
},
{
"target": "0x59E16fcCd424Cc24e280Be16E11Bcd56fb0CE547",
"calldata": "0xf2fde38b00000000000000000000000062627681d92e36b9aee1d9a6bf181373ccd42552",
"value": "0",
"signature": ""
},
{
"target": "0x283Af0B28c62C092C9727F1Ee09c02CA627EB7F5",
"calldata": "0xf2fde38b00000000000000000000000062627681d92e36b9aee1d9a6bf181373ccd42552",
"value": "0",
"signature": ""
},
{
"target": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64",
"calldata": "0x6a761202000000000000000000000000703806e61847984346d2d7ddd853049627e50a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000440c6c76b84d414e4147455200000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b700000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000",
"value": "0",
"signature": ""
},
{
"target": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64",
"calldata": "0x6a761202000000000000000000000000703806e61847984346d2d7ddd853049627e50a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000003247508dd984d414e4147455200000000000000000000000000000000000000000000000000000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48a9059cbb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b700000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000",
"value": "0",
"signature": ""
},
{
"target": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64",
"calldata": "0x6a761202000000000000000000000000703806e61847984346d2d7ddd853049627e50a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000440c6c76b84d414e4147455200000000000000000000000000000000000000000000000000000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b700000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000",
"value": "0",
"signature": ""
},
{
"target": "0x4F2083f5fBede34C2714aFfb3105539775f7FE64",
"calldata": "0x6a761202000000000000000000000000703806e61847984346d2d7ddd853049627e50a400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000084b3dd25c74d414e4147455200000000000000000000000000000000000000000000000000000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041000000000000000000000000fe89cc7abb2c4183683ab71653c4cdc9b02d44b700000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000",
"value": "0",
"signature": ""
}
]
}
Loading