Skip to content

Commit

Permalink
feat: forbidBoundsUpdate in controller timelock
Browse files Browse the repository at this point in the history
  • Loading branch information
lekhovitsky committed Oct 23, 2023
1 parent 24f26f2 commit e9622d1
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
19 changes: 19 additions & 0 deletions contracts/governance/ControllerTimelockV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,25 @@ contract ControllerTimelockV3 is PolicyManagerV3, IControllerTimelockV3 {
}); // U:[CT-16]
}

/// @notice Queues a transaction to forbid permissionless bounds update in an LP price feed
/// @dev Requires the policy for keccak(group(priceFeed), "UPDATE_BOUNDS_ALLOWED") to be enabled,
/// otherwise auto-fails the check
/// @param priceFeed The price feed to forbid bounds update for
function forbidBoundsUpdate(address priceFeed) external override {
if (!_checkPolicy(priceFeed, "UPDATE_BOUNDS_ALLOWED", 0, 0)) {
revert ParameterChecksFailedException(); // U:[CT-17]
}

_queueTransaction({
target: priceFeed,
signature: "forbidBoundsUpdate()",
data: "",
delay: _getPolicyDelay(priceFeed, "UPDATE_BOUNDS_ALLOWED"),
sanityCheckValue: 0,
sanityCheckCallData: ""
}); // U:[CT-17]
}

/// @dev Internal function that stores the transaction in the queued tx map
/// @param target The contract to call
/// @param signature The signature of the called function
Expand Down
2 changes: 2 additions & 0 deletions contracts/interfaces/IControllerTimelockV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ interface IControllerTimelockV3 is IControllerTimelockV3Events, IVersion {

function setReservePriceFeedStatus(address priceOracle, address token, bool active) external;

function forbidBoundsUpdate(address priceFeed) external;

// --------- //
// EXECUTION //
// --------- //
Expand Down
72 changes: 71 additions & 1 deletion contracts/test/unit/governance/ControllerTimelock.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ contract ControllerTimelockTest is Test, IControllerTimelockV3Events {

/// @dev U:[CT-5]: setCreditManagerDebtLimit works correctly
function test_U_CT_05_setCreditManagerDebtLimit_works_correctly() public {
(address creditManager, address creditFacade,, address pool,) = _makeMocks();
(address creditManager, /* address creditFacade */,, address pool,) = _makeMocks();

// TODO: double check
// vm.mockCall(creditFacade, abi.encodeCall(ICreditFacadeV3.trackTotalDebt, ()), abi.encode(false));
Expand Down Expand Up @@ -1676,4 +1676,74 @@ contract ControllerTimelockTest is Test, IControllerTimelockV3Events {

assertTrue(!queued, "Transaction is still queued after execution");
}

/// @dev U:[CT-17]: forbidBoundsUpdate works correctly
function test_U_CT_17_forbidBoundsUpdate_works_correctly() public {
address priceFeed = makeAddr("PRICE_FEED");
vm.mockCall(priceFeed, abi.encodeWithSignature("forbidBoundsUpdate()"), "");

vm.prank(CONFIGURATOR);
controllerTimelock.setGroup(priceFeed, "PRICE_FEED");

bytes32 POLICY_CODE = keccak256(abi.encode("PRICE_FEED", "UPDATE_BOUNDS_ALLOWED"));

Policy memory policy = Policy({
enabled: false,
admin: admin,
delay: 1 days,
flags: 0,
exactValue: 0,
minValue: 0,
maxValue: 0,
referencePoint: 0,
referencePointUpdatePeriod: 0,
referencePointTimestampLU: 0,
minPctChangeDown: 0,
minPctChangeUp: 0,
maxPctChangeDown: 0,
maxPctChangeUp: 0,
minChange: 0,
maxChange: 0
});

// VERIFY THAT THE FUNCTION CANNOT BE CALLED WITHOUT RESPECTIVE POLICY
vm.expectRevert(ParameterChecksFailedException.selector);
vm.prank(admin);
controllerTimelock.forbidBoundsUpdate(priceFeed);

vm.prank(CONFIGURATOR);
controllerTimelock.setPolicy(POLICY_CODE, policy);

// VERIFY THAT THE FUNCTION IS ONLY CALLABLE BY ADMIN
vm.expectRevert(ParameterChecksFailedException.selector);
vm.prank(USER);
controllerTimelock.forbidBoundsUpdate(priceFeed);

// VERIFY THAT THE FUNCTION IS QUEUED AND EXECUTED CORRECTLY
bytes32 txHash = keccak256(abi.encode(admin, priceFeed, "forbidBoundsUpdate()", "", block.timestamp + 1 days));

vm.expectEmit(true, false, false, true);
emit QueueTransaction(txHash, admin, priceFeed, "forbidBoundsUpdate()", "", uint40(block.timestamp + 1 days));

vm.prank(admin);
controllerTimelock.forbidBoundsUpdate(priceFeed);

(,,,,,, uint256 sanityCheckValue, bytes memory sanityCheckCallData) =
controllerTimelock.queuedTransactions(txHash);

assertEq(sanityCheckValue, 0, "Sanity check value written incorrectly");

assertEq(sanityCheckCallData, "");

vm.expectCall(priceFeed, abi.encodeWithSignature("forbidBoundsUpdate()"));

vm.warp(block.timestamp + 1 days);

vm.prank(admin);
controllerTimelock.executeTransaction(txHash);

(bool queued,,,,,,,) = controllerTimelock.queuedTransactions(txHash);

assertTrue(!queued, "Transaction is still queued after execution");
}
}

0 comments on commit e9622d1

Please sign in to comment.