Skip to content

Commit

Permalink
feat(ddm-disable): add single DDM disable spell
Browse files Browse the repository at this point in the history
  • Loading branch information
amusingaxl committed May 22, 2024
1 parent efec4e7 commit 5b57421
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 0 deletions.
70 changes: 70 additions & 0 deletions src/ddm-disable/SingleDdmDisableSpell.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-FileCopyrightText: © 2024 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.16;

import {DssEmergencySpell} from "../DssEmergencySpell.sol";

interface DdmMomLike {
function disable(address plan) external;
}

interface DdmPlanLike {
function active() external view returns (bool);
function disable() external;
}

interface DdmHubLike {
function plan(bytes32 ilk) external view returns (address plan);
}

contract SingleDdmDisableSpell is DssEmergencySpell {
DdmMomLike public immutable ddmMom = DdmMomLike(_log.getAddress("DIRECT_MOM"));
DdmHubLike public immutable ddmHub = DdmHubLike(_log.getAddress("DIRECT_HUB"));
bytes32 public immutable ilk;

event Disable(address indexed plan);

constructor(bytes32 _ilk) {
ilk = _ilk;
}

function description() external view returns (string memory) {
return string(abi.encodePacked("Emergency Spell | Disable DDM Plan: ", ilk));
}

function _emeregencyActions() internal override {
address plan = ddmHub.plan(ilk);
ddmMom.disable(plan);
emit Disable(plan);
}

/**
* @notice Returns whether the spell is done or not.
* @dev Checks if the plan instance has stopped = 3.
*/
function done() external view returns (bool) {
return !DdmPlanLike(ddmHub.plan(ilk)).active();
}
}

contract SingleDdmDisableFactory {
event Deploy(bytes32 indexed ilk, address spell);

function deploy(bytes32 ilk) external returns (address spell) {
spell = address(new SingleDdmDisableSpell(ilk));
emit Deploy(ilk, spell);
}
}
91 changes: 91 additions & 0 deletions src/ddm-disable/SingleDdmDisableSpell.t.integration.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: © 2024 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.16;

import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {DssTest, DssInstance, MCD, GodMode} from "dss-test/DssTest.sol";
import {DssEmergencySpellLike} from "../DssEmergencySpell.sol";
import {SingleDdmDisableFactory} from "./SingleDdmDisableSpell.sol";

interface DdmMomLike {
function disable(address plan) external;
}

interface DdmHubLike {
function plan(bytes32 ilk) external view returns (address);
}

interface DdmPlanLike {
function active() external view returns (bool);
}

contract SingleDdmDisableSpellTest is DssTest {
using stdStorage for StdStorage;

address constant CHAINLOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;
DssInstance dss;
address chief;
bytes32 ilk = "DIRECT-SPARK-DAI";
DdmMomLike ddmMom;
DdmHubLike ddmHub;
DdmPlanLike plan;
SingleDdmDisableFactory factory;
DssEmergencySpellLike spell;

function setUp() public {
vm.createSelectFork("mainnet");

dss = MCD.loadFromChainlog(CHAINLOG);
MCD.giveAdminAccess(dss);
chief = dss.chainlog.getAddress("MCD_ADM");
ddmMom = DdmMomLike(dss.chainlog.getAddress("DIRECT_MOM"));
ddmHub = DdmHubLike(dss.chainlog.getAddress("DIRECT_HUB"));
plan = DdmPlanLike(ddmHub.plan(ilk));
factory = new SingleDdmDisableFactory();
spell = DssEmergencySpellLike(factory.deploy(ilk));

stdstore.target(chief).sig("hat()").checked_write(address(spell));

vm.makePersistent(chief);
}

function testDdmDisableOnSchedule() public {
assertTrue(plan.active(), "before: plan already disabled");
assertFalse(spell.done(), "before: spell already done");

vm.expectEmit(true, true, true, true);
emit Disable(address(plan));
spell.schedule();

assertFalse(plan.active(), "after: plan not disabled");
assertTrue(spell.done(), "after: spell not done");
}

function testRevertDdmDisableWhenItDoesNotHaveTheHat() public {
stdstore.target(chief).sig("hat()").checked_write(address(0));

assertTrue(plan.active(), "before: plan already disabled");
assertFalse(spell.done(), "before: spell already done");

vm.expectRevert();
spell.schedule();

assertTrue(plan.active(), "after: plan disabled unexpectedly");
assertFalse(spell.done(), "after: spell done unexpectedly");
}

event Disable(address indexed plan);
}

0 comments on commit 5b57421

Please sign in to comment.