Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow triggering multiple times after the module has been triggered once #4

Merged
merged 2 commits into from
Mar 18, 2024
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
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
82 changes: 48 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,29 @@ 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
hexonaut marked this conversation as resolved.
Show resolved Hide resolved

// Only update what has changed
reserves[4].active = true;
reserves[4].borrowingEnabled = false;

for (uint256 i = 0; i < reserves.length; i++) {
_assertReserve(reserves[i]);
}
}

function _initReserve(ReserveConfigParams memory params) internal {
Expand Down
Loading