Skip to content

Commit

Permalink
allow triggering multiple times after the module has been triggered once
Browse files Browse the repository at this point in the history
  • Loading branch information
hexonaut committed Mar 17, 2024
1 parent 0f0be3f commit b19b821
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 47 deletions.
19 changes: 10 additions & 9 deletions src/KillSwitchOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,18 @@ contract KillSwitchOracle is IKillSwitchOracle, Ownable {
/******************************************************************************************************************/

function trigger(address oracle) external override {
require(!triggered, "KillSwitchOracle/already-triggered");
// Once triggered, the kill switch can be used to disable all borrowing until it is reset
if (!triggered) {
uint256 threshold = oracleThresholds[oracle];
require(threshold != 0, "KillSwitchOracle/oracle-does-not-exist");

uint256 threshold = oracleThresholds[oracle];
require(threshold != 0, "KillSwitchOracle/oracle-does-not-exist");
int256 price = AggregatorInterface(oracle).latestAnswer();
require(price > 0, "KillSwitchOracle/invalid-price");
require(uint256(price) <= threshold, "KillSwitchOracle/price-above-threshold");

int256 price = AggregatorInterface(oracle).latestAnswer();
require(price > 0, "KillSwitchOracle/invalid-price");
require(uint256(price) <= threshold, "KillSwitchOracle/price-above-threshold");

triggered = true;
emit Trigger(oracle, threshold, uint256(price));
triggered = true;
emit Trigger(oracle, threshold, uint256(price));
}

address[] memory assets = pool.getReservesList();
for (uint256 i = 0; i < assets.length; i++) {
Expand Down
10 changes: 6 additions & 4 deletions src/interfaces/IKillSwitchOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ interface IKillSwitchOracle {
function disableOracle(address oracle) external;

/**
* @dev Resets the trigger, allowing the kill switch to be triggered again.
* @dev Reset the module so that the kill switch can only be triggered if one of
* the oracles is below the threshold.
*/
function reset() external;

Expand Down Expand Up @@ -132,9 +133,10 @@ interface IKillSwitchOracle {
* @notice Permissionless function to trigger the kill switch.
* @dev If the kill switch has not been triggered, the oracle threshold has been defined,
* and the oracle is below the threshold, the kill switch is triggered. This will
* disable borrowing on all assets. This function can only be called once and will
* require a call to `reset()` by the owner to be called again.
* @param oracle The address of the oracle which is below the threshold.
* disable borrowing on all assets. If the kill switch has been triggered, this
* function will allow disabling borrowing on all assets until the kill switch is reset.
* @param oracle The address of the oracle which is below the threshold. If the kill switch
* has been triggered, this parameter is ignored.
*/
function trigger(address oracle) external;

Expand Down
74 changes: 40 additions & 34 deletions test/KillSwitchOracle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,6 @@ contract KillSwitchOracleTriggerTests is KillSwitchOracleTestBase {

using ReserveConfiguration for DataTypes.ReserveConfigurationMap;

function test_trigger_alreadyTriggered() public {
vm.prank(owner);
killSwitchOracle.setOracle(address(oracle1), 1e8);
killSwitchOracle.trigger(address(oracle1));

vm.expectRevert("KillSwitchOracle/already-triggered");
killSwitchOracle.trigger(address(oracle1));
}

function test_trigger_doesNotExist() public {
vm.prank(owner);
vm.expectRevert("KillSwitchOracle/oracle-does-not-exist");
Expand Down Expand Up @@ -310,43 +301,43 @@ contract KillSwitchOracleTriggerTests is KillSwitchOracleTestBase {
ReserveConfigParams[5] memory reserves = [
// Asset with borrow enabled (Ex. ETH, wstETH, DAI)
ReserveConfigParams({
asset: asset1,
active: true,
frozen: false,
paused: false,
borrowingEnabled: true
asset: asset1,
active: true,
frozen: false,
paused: false,
borrowingEnabled: true
}),
// Collateral-only asset (Ex. sDAI)
ReserveConfigParams({
asset: asset2,
active: true,
frozen: false,
paused: false,
borrowingEnabled: false
asset: asset2,
active: true,
frozen: false,
paused: false,
borrowingEnabled: false
}),
// Frozen asset (Ex. GNO)
ReserveConfigParams({
asset: asset3,
active: true,
frozen: true,
paused: false,
borrowingEnabled: true
asset: asset3,
active: true,
frozen: true,
paused: false,
borrowingEnabled: true
}),
// Paused asset
ReserveConfigParams({
asset: asset4,
active: true,
frozen: false,
paused: true,
borrowingEnabled: true
asset: asset4,
active: true,
frozen: false,
paused: true,
borrowingEnabled: true
}),
// Inactive asset
ReserveConfigParams({
asset: asset5,
active: false,
frozen: false,
paused: false,
borrowingEnabled: false
asset: asset5,
active: false,
frozen: false,
paused: false,
borrowingEnabled: false
})
];

Expand All @@ -373,6 +364,21 @@ contract KillSwitchOracleTriggerTests is KillSwitchOracleTestBase {
for (uint256 i = 0; i < reserves.length; i++) {
_assertReserve(reserves[i]);
}

// New reserve has been added after the trigger (perhaps a pending spell)
_initReserve(ReserveConfigParams({
asset: asset5,
active: true,
frozen: false,
paused: false,
borrowingEnabled: true
}));

// Should be able to disable borrowing on this new asset
vm.expectEmit(address(killSwitchOracle));
emit BorrowDisabled(asset5);
vm.prank(randomAddress); // Permissionless call
killSwitchOracle.trigger(address(0)); // Second trigger oracle address can be anything
}

function _initReserve(ReserveConfigParams memory params) internal {
Expand Down

0 comments on commit b19b821

Please sign in to comment.