From 78268142bb6f3054e821233a9c460b797253f6e0 Mon Sep 17 00:00:00 2001
From: amusingaxl <112016538+amusingaxl@users.noreply.github.com>
Date: Thu, 28 Nov 2024 12:59:20 -0300
Subject: [PATCH] refactor: rename `Batched` spells as `Grouped`; switch to
dynamic storage ilk list
---
README.md | 18 +++-
...Spell.sol => DssGroupedEmergencySpell.sol} | 86 +++++++++----------
...ssGroupedEmergencySpell.t.integration.sol} | 77 ++++++++++++++---
...rSpell.sol => GroupedClipBreakerSpell.sol} | 30 +++----
...GroupedClipBreakerSpell.t.integration.sol} | 20 ++---
...WipeSpell.sol => GroupedLineWipeSpell.sol} | 28 +++---
...=> GroupedLineWipeSpell.t.integration.sol} | 20 ++---
7 files changed, 168 insertions(+), 111 deletions(-)
rename src/{DssBatchedEmergencySpell.sol => DssGroupedEmergencySpell.sol} (61%)
rename src/{DssBatchedEmergencySpell.t.integration.sol => DssGroupedEmergencySpell.t.integration.sol} (61%)
rename src/clip-breaker/{BatchedClipBreakerSpell.sol => GroupedClipBreakerSpell.sol} (80%)
rename src/clip-breaker/{BatchedClipBreakerSpell.t.integration.sol => GroupedClipBreakerSpell.t.integration.sol} (91%)
rename src/line-wipe/{BatchedLineWipeSpell.sol => GroupedLineWipeSpell.sol} (79%)
rename src/line-wipe/{BatchedLineWipeSpell.t.integration.sol => GroupedLineWipeSpell.t.integration.sol} (92%)
diff --git a/README.md b/README.md
index 1f07f88..e8048f3 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ TBD.
## Implemented Actions
-| Description | Single-ilk | Batched | Multi-ilk / Global |
+| Description | Single-ilk | Grouped | Multi-ilk / Global |
| :---------- | :--------: | :-----: | :----------------: |
| Wipe `line` | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Set `Clip` breaker | :white_check_mark: | :white_check_mark: | :white_check_mark: |
@@ -123,12 +123,24 @@ constructor.
Some types of emergency spells may come in 3 flavors:
1. Single-ilk: applies the desired spell action to a single pre-defined ilk.
-1. Batched: applies the desired spell action to a list of related ilks (i.e.: `ETH-A`, `ETH-B` and `ETH-C`)
+1. Grouped: applies the desired spell action to a list of related ilks (i.e.: `ETH-A`, `ETH-B` and `ETH-C`)
1. Multi: applies the desired spell action to all applicable ilks.
Furthermore, this repo provides on-chain factories for single ilk emergency spells to make it easier to deploy for new
ilks.
+
+### About storage variables in `DssGroupedEmergencySpell`
+
+Regular spell actions are executed through a `delegatecall` from `MCD_PAUSE_PROXY`. For that reason, they usually should
+not have storage variables, as they would be accessing and interacting with `MCD_PAUSE_PROXY`'s storage, not their own.
+
+However, Emergency Spells are not required to interact with `MCD_PAUSE` and `MCD_PAUSE_PROXY` at all. They execute
+actions through regular `call` on `Mom` contracts, so we do not have this limitation.
+
+Even if the contract is somehow misused and used as a regular spell, interacting with `MCD_PAUSE`, there would not be a
+problem because the storage should not be changed outside the constructor by the concrete implementations.
+
### About the `done()` function
Conforming spells have a [`done`][spell-done] public storage variable which is `false` when the spell is deployed and
@@ -138,7 +150,7 @@ An emergency spell is not meant to be cast, but it can be scheduled multiple tim
storage variable, it becomes a getter function that will return:
- `false`: if the emergency spell can be scheduled in the current state, given it is lifted to the hat.
- `true`: if the desired effects of the spell can be verified or if there is anything that would prevent the spell from
- being scheduled (i.e.: bad system config)
+ being scheduled (i.e.: bad system config).
Generally speaking, `done` should almost always return `false` for any emergency spell. If it returns `true` it means it
has just been scheduled or there is most likely something wrong with the modules touched by it. The exception is the
diff --git a/src/DssBatchedEmergencySpell.sol b/src/DssGroupedEmergencySpell.sol
similarity index 61%
rename from src/DssBatchedEmergencySpell.sol
rename to src/DssGroupedEmergencySpell.sol
index ad622c3..c6dda43 100644
--- a/src/DssBatchedEmergencySpell.sol
+++ b/src/DssGroupedEmergencySpell.sol
@@ -17,34 +17,30 @@ pragma solidity ^0.8.16;
import {DssEmergencySpell, DssEmergencySpellLike} from "./DssEmergencySpell.sol";
-interface DssBatchedEmergencySpellLike is DssEmergencySpellLike {
+interface DssGroupedEmergencySpellLike is DssEmergencySpellLike {
function ilks() external view returns (bytes32[] memory);
+ function emergencyActionsInBatch(uint256 start, uint256 end) external;
}
-/// @title Batched Emergency Spell
-/// @notice Defines the base implementation for batched emergency spells.
+/// @title Grouped Emergency Spell
+/// @notice Defines the base implementation for grouped emergency spells.
/// @custom:authors [amusingaxl]
/// @custom:reviewers []
/// @custom:auditors []
/// @custom:bounties []
-abstract contract DssBatchedEmergencySpell is DssEmergencySpell, DssBatchedEmergencySpellLike {
+abstract contract DssGroupedEmergencySpell is DssEmergencySpell, DssGroupedEmergencySpellLike {
/// @dev The min size for the list of ilks
- uint256 public constant MIN_ILKS = 2;
- /// @dev The max size for the list of ilks
- uint256 public constant MAX_ILKS = 3;
-
- /// @dev The total number of ilks in the spell.
- uint256 internal immutable _totalIlks;
- /// @dev The 0th ilk to which the spell should be applicable.
- bytes32 internal immutable _ilk0;
- /// @dev The 1st ilk to which the spell should be applicable.
- bytes32 internal immutable _ilk1;
- /// @dev The 2nd ilk to which the spell should be applicable.
- bytes32 internal immutable _ilk2;
+ uint256 private constant MIN_ILKS = 1;
+
+ /// @notice The list of ilks to which the spell is applicable.
+ /// @dev While spells should not have storage variables, we can make an exception here because this spell should not
+ /// change its own storage, an therefore, could not overwrite the PauseProxy state through delegate call even
+ /// if used incorrectly.
+ bytes32[] private ilkList;
/// @param _ilks The list of ilks for which the spell should be applicable
/// @dev The list size is be at least 2 and less than or equal to 3.
- /// The batched spell is meant to be used for ilks that are a variation of tha same collateral gem
+ /// The grouped spell is meant to be used for ilks that are a variation of tha same collateral gem
/// (i.e.: ETH-A, ETH-B, ETH-C)
/// There has never been a case where MCD onboarded 4 or more ilks for the same collateral gem.
/// For cases where there is only one ilk for the same collateral gem, use the single-ilk version.
@@ -52,33 +48,23 @@ abstract contract DssBatchedEmergencySpell is DssEmergencySpell, DssBatchedEmerg
// This is a workaround to Solidity's lack of support for immutable arrays, as described in
// https://github.com/ethereum/solidity/issues/12587
uint256 len = _ilks.length;
- require(len >= MIN_ILKS, "DssBatchedEmergencySpell/too-few-ilks");
- require(len <= MAX_ILKS, "DssBatchedEmergencySpell/too-many-ilks");
- _totalIlks = len;
-
- _ilk0 = _ilks[0];
- _ilk1 = _ilks[1];
- // Only ilk2 is not guaranteed to exist.
- _ilk2 = len > 2 ? _ilks[2] : bytes32(0);
+ require(len >= MIN_ILKS, "DssGroupedEmergencySpell/too-few-ilks");
+
+ ilkList = _ilks;
}
/// @notice Returns the list of ilks to which the spell is applicable.
- /// @return _ilks The list of ilks
- function ilks() public view returns (bytes32[] memory _ilks) {
- _ilks = new bytes32[](_totalIlks);
- _ilks[0] = _ilk0;
- _ilks[1] = _ilk1;
- if (_totalIlks > 2) {
- _ilks[2] = _ilk2;
- }
+ function ilks() external view returns (bytes32[] memory) {
+ return ilkList;
}
/// @notice Returns the spell description.
function description() external view returns (string memory) {
// Join the list of ilks into a comma-separated string
- string memory buf = string.concat(_bytes32ToString(_ilk0), ", ", _bytes32ToString(_ilk1));
- if (_totalIlks > 2) {
- buf = string.concat(buf, ", ", _bytes32ToString(_ilk2));
+ string memory buf = _bytes32ToString(ilkList[0]);
+ // Start from one because the first item was already added.
+ for (uint256 i = 1; i < ilkList.length; i++) {
+ buf = string.concat(buf, ", ", _bytes32ToString(ilkList[i]));
}
return string.concat(_descriptionPrefix(), " ", buf);
@@ -106,10 +92,24 @@ abstract contract DssBatchedEmergencySpell is DssEmergencySpell, DssBatchedEmerg
/// @inheritdoc DssEmergencySpell
function _emergencyActions() internal override {
- _emergencyActions(_ilk0);
- _emergencyActions(_ilk1);
- if (_totalIlks > 2) {
- _emergencyActions(_ilk2);
+ for (uint256 i = 0; i < ilkList.length; i++) {
+ _emergencyActions(ilkList[i]);
+ }
+ }
+
+ /**
+ * @notice Executes the emergency actions for all ilks in the batch.
+ * @dev This is an escape hatch to prevent the spell from being blocked in case it would hit the block gas limit.
+ * In case `end` is greater than the ilk registry length, the iteration will be automatically capped.
+ * @param start The index to start the iteration (inclusive).
+ * @param end The index to stop the iteration (inclusive).
+ */
+ function emergencyActionsInBatch(uint256 start, uint256 end) external {
+ end = end > ilkList.length - 1 ? ilkList.length - 1 : end;
+ require(start <= end, "DssGroupedEmergencySpell/bad-iteration");
+
+ for (uint256 i = start; i <= end; i++) {
+ _emergencyActions(ilkList[i]);
}
}
@@ -120,9 +120,9 @@ abstract contract DssBatchedEmergencySpell is DssEmergencySpell, DssBatchedEmerg
/// @notice Returns whether the spell is done for all ilks or not.
/// @return res Whether the spells is done or not.
function done() external view returns (bool res) {
- res = _done(_ilk0) && _done(_ilk1);
- if (_totalIlks > 2) {
- res = res && _done(_ilk2);
+ res = true;
+ for (uint256 i = 0; i < ilkList.length; i++) {
+ res = res && _done(ilkList[i]);
}
}
diff --git a/src/DssBatchedEmergencySpell.t.integration.sol b/src/DssGroupedEmergencySpell.t.integration.sol
similarity index 61%
rename from src/DssBatchedEmergencySpell.t.integration.sol
rename to src/DssGroupedEmergencySpell.t.integration.sol
index c71cd53..1add72b 100644
--- a/src/DssBatchedEmergencySpell.t.integration.sol
+++ b/src/DssGroupedEmergencySpell.t.integration.sol
@@ -17,37 +17,39 @@ pragma solidity ^0.8.16;
import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {DssTest, DssInstance, MCD, GodMode} from "dss-test/DssTest.sol";
-import {DssBatchedEmergencySpell} from "./DssBatchedEmergencySpell.sol";
+import {DssGroupedEmergencySpell} from "./DssGroupedEmergencySpell.sol";
-contract DssBatchedEmergencySpellImpl is DssBatchedEmergencySpell {
- mapping(bytes32 => bool) internal _isDone;
+contract DssGroupedEmergencySpellImpl is DssGroupedEmergencySpell {
+ mapping(bytes32 => bool) public isDone;
function setDone(bytes32 ilk, bool val) external {
- _isDone[ilk] = val;
+ isDone[ilk] = val;
}
function _descriptionPrefix() internal pure override returns (string memory) {
- return "Batched Emergency Spell:";
+ return "Grouped Emergency Spell:";
}
event EmergencyAction(bytes32 indexed ilk);
- constructor(bytes32[] memory _ilks) DssBatchedEmergencySpell(_ilks) {}
+ constructor(bytes32[] memory _ilks) DssGroupedEmergencySpell(_ilks) {}
function _emergencyActions(bytes32 ilk) internal override {
emit EmergencyAction(ilk);
+ isDone[ilk] = true;
}
function _done(bytes32 ilk) internal view override returns (bool) {
- return _isDone[ilk];
+ return isDone[ilk];
}
}
-contract DssBatchedEmergencySpellTest is DssTest {
+contract DssGroupedEmergencySpellTest is DssTest {
address constant CHAINLOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;
DssInstance dss;
- DssBatchedEmergencySpellImpl spell2;
- DssBatchedEmergencySpellImpl spell3;
+ DssGroupedEmergencySpellImpl spell2;
+ DssGroupedEmergencySpellImpl spell3;
+ DssGroupedEmergencySpellImpl spellN;
address pause;
function setUp() public {
@@ -60,17 +62,27 @@ contract DssBatchedEmergencySpellTest is DssTest {
bytes32[] memory ilks2 = new bytes32[](2);
ilks2[0] = "WSTETH-A";
ilks2[1] = "WSTETH-B";
- spell2 = new DssBatchedEmergencySpellImpl(ilks2);
+ spell2 = new DssGroupedEmergencySpellImpl(ilks2);
bytes32[] memory ilks3 = new bytes32[](3);
ilks3[0] = "ETH-A";
ilks3[1] = "ETH-B";
ilks3[2] = "ETH-C";
- spell3 = new DssBatchedEmergencySpellImpl(ilks3);
+ spell3 = new DssGroupedEmergencySpellImpl(ilks3);
+ bytes32[] memory ilksN = new bytes32[](8);
+ ilksN[0] = "ETH-A";
+ ilksN[1] = "ETH-B";
+ ilksN[2] = "ETH-C";
+ ilksN[3] = "WSTETH-A";
+ ilksN[4] = "WSTETH-B";
+ ilksN[5] = "WBTC-A";
+ ilksN[6] = "WBTC-B";
+ ilksN[7] = "WBTC-C";
+ spellN = new DssGroupedEmergencySpellImpl(ilksN);
}
function testDescription() public view {
- assertEq(spell2.description(), "Batched Emergency Spell: WSTETH-A, WSTETH-B");
- assertEq(spell3.description(), "Batched Emergency Spell: ETH-A, ETH-B, ETH-C");
+ assertEq(spell2.description(), "Grouped Emergency Spell: WSTETH-A, WSTETH-B");
+ assertEq(spell3.description(), "Grouped Emergency Spell: ETH-A, ETH-B, ETH-C");
}
function testEmergencyActions() public {
@@ -87,6 +99,43 @@ contract DssBatchedEmergencySpellTest is DssTest {
vm.expectEmit(true, true, true, true);
emit EmergencyAction("ETH-C");
spell3.schedule();
+
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("ETH-A");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("ETH-B");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("ETH-C");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("WSTETH-A");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("WSTETH-B");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("WBTC-A");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("WBTC-B");
+ vm.expectEmit(true, true, true, true);
+ emit EmergencyAction("WBTC-C");
+ spellN.schedule();
+ }
+
+ function testEmergencyActionsInBatches_Fuzz(uint256 batchSize) public {
+ uint256 count = spellN.ilks().length;
+ batchSize = bound(batchSize, 1, count);
+ uint256 start = 0;
+ // End is inclusive, so we need to subtract 1
+ uint256 end = start + batchSize - 1;
+
+ assertFalse(spellN.done(), "spellN unexpectedly done");
+
+ while (start < count) {
+ spellN.emergencyActionsInBatch(start, end);
+
+ start += batchSize;
+ end += batchSize;
+ }
+
+ assertTrue(spellN.done(), "spellN not done");
}
function testDone() public {
diff --git a/src/clip-breaker/BatchedClipBreakerSpell.sol b/src/clip-breaker/GroupedClipBreakerSpell.sol
similarity index 80%
rename from src/clip-breaker/BatchedClipBreakerSpell.sol
rename to src/clip-breaker/GroupedClipBreakerSpell.sol
index fce4581..d10f8f2 100644
--- a/src/clip-breaker/BatchedClipBreakerSpell.sol
+++ b/src/clip-breaker/GroupedClipBreakerSpell.sol
@@ -15,7 +15,7 @@
// along with this program. If not, see .
pragma solidity ^0.8.16;
-import {DssBatchedEmergencySpell} from "../DssBatchedEmergencySpell.sol";
+import {DssGroupedEmergencySpell} from "../DssGroupedEmergencySpell.sol";
interface ClipperMomLike {
function setBreaker(address clip, uint256 level, uint256 delay) external;
@@ -30,13 +30,13 @@ interface IlkRegistryLike {
function xlip(bytes32 ilk) external view returns (address);
}
-/// @title Emergency Spell: Batched Clip Breaker
+/// @title Emergency Spell: Grouped Clip Breaker
/// @notice Prevents further collateral auctions to be held in the respective Clip contracts.
/// @custom:authors [amusingaxl]
/// @custom:reviewers []
/// @custom:auditors []
/// @custom:bounties []
-contract BatchedClipBreakerSpell is DssBatchedEmergencySpell {
+contract GroupedClipBreakerSpell is DssGroupedEmergencySpell {
/// @notice The ClipperMom from chainlog.
ClipperMomLike public immutable clipperMom = ClipperMomLike(_log.getAddress("CLIPPER_MOM"));
/// @notice The IlkRegistry from chainlog.
@@ -54,19 +54,17 @@ contract BatchedClipBreakerSpell is DssBatchedEmergencySpell {
/// @param _ilks The list of ilks for which the spell should be applicable
/// @dev The list size is be at least 2 and less than or equal to 3.
- /// The batched spell is meant to be used for ilks that are a variation of tha same collateral gem
+ /// The grouped spell is meant to be used for ilks that are a variation of tha same collateral gem
/// (i.e.: ETH-A, ETH-B, ETH-C)
- /// There has never been a case where MCD onboarded 4 or more ilks for the same collateral gem.
- /// For cases where there is only one ilk for the same collateral gem, use the single-ilk version.
- constructor(bytes32[] memory _ilks) DssBatchedEmergencySpell(_ilks) {}
+ constructor(bytes32[] memory _ilks) DssGroupedEmergencySpell(_ilks) {}
- /// @inheritdoc DssBatchedEmergencySpell
+ /// @inheritdoc DssGroupedEmergencySpell
function _descriptionPrefix() internal pure override returns (string memory) {
- return "Emergency Spell | Batched Clip Breaker:";
+ return "Emergency Spell | Grouped Clip Breaker:";
}
/// @notice Sets the breaker for the related Clip contract.
- /// @inheritdoc DssBatchedEmergencySpell
+ /// @inheritdoc DssGroupedEmergencySpell
function _emergencyActions(bytes32 _ilk) internal override {
address clip = ilkReg.xlip(_ilk);
clipperMom.setBreaker(clip, BREAKER_LEVEL, BREAKER_DELAY);
@@ -99,22 +97,22 @@ contract BatchedClipBreakerSpell is DssBatchedEmergencySpell {
}
}
-/// @title Emergency Spell Factory: Batched Clip Breaker
-/// @notice On-chain factory to deploy Batched Clip Breaker emergency spells.
+/// @title Emergency Spell Factory: Grouped Clip Breaker
+/// @notice On-chain factory to deploy Grouped Clip Breaker emergency spells.
/// @custom:authors [amusingaxl]
/// @custom:reviewers []
/// @custom:auditors []
/// @custom:bounties []
-contract BatchedClipBreakerFactory {
- /// @notice A new BatchedClipBreakerSpell has been deployed.
+contract GroupedClipBreakerFactory {
+ /// @notice A new GroupedClipBreakerSpell has been deployed.
/// @param ilks The list of ilks for which the spell is applicable.
/// @param spell The deployed spell address.
event Deploy(bytes32[] indexed ilks, address spell);
- /// @notice Deploys a BatchedClipBreakerSpell contract.
+ /// @notice Deploys a GroupedClipBreakerSpell contract.
/// @param ilks The list of ilks for which the spell is applicable.
function deploy(bytes32[] memory ilks) external returns (address spell) {
- spell = address(new BatchedClipBreakerSpell(ilks));
+ spell = address(new GroupedClipBreakerSpell(ilks));
emit Deploy(ilks, spell);
}
}
diff --git a/src/clip-breaker/BatchedClipBreakerSpell.t.integration.sol b/src/clip-breaker/GroupedClipBreakerSpell.t.integration.sol
similarity index 91%
rename from src/clip-breaker/BatchedClipBreakerSpell.t.integration.sol
rename to src/clip-breaker/GroupedClipBreakerSpell.t.integration.sol
index e248d01..b0351cc 100644
--- a/src/clip-breaker/BatchedClipBreakerSpell.t.integration.sol
+++ b/src/clip-breaker/GroupedClipBreakerSpell.t.integration.sol
@@ -18,7 +18,7 @@ pragma solidity ^0.8.16;
import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {DssTest, DssInstance, MCD} from "dss-test/DssTest.sol";
import {DssEmergencySpellLike} from "../DssEmergencySpell.sol";
-import {BatchedClipBreakerSpell, BatchedClipBreakerFactory} from "./BatchedClipBreakerSpell.sol";
+import {GroupedClipBreakerSpell, GroupedClipBreakerFactory} from "./GroupedClipBreakerSpell.sol";
interface IlkRegistryLike {
function xlip(bytes32 ilk) external view returns (address);
@@ -34,7 +34,7 @@ interface ClipLike {
function deny(address who) external;
}
-abstract contract BatchedClipBreakerSpellTest is DssTest {
+abstract contract GroupedClipBreakerSpellTest is DssTest {
using stdStorage for StdStorage;
address constant CHAINLOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;
@@ -47,7 +47,7 @@ abstract contract BatchedClipBreakerSpellTest is DssTest {
ClipLike clipA;
ClipLike clipB;
ClipLike clipC;
- BatchedClipBreakerFactory factory;
+ GroupedClipBreakerFactory factory;
DssEmergencySpellLike spell;
function setUp() public {
@@ -60,7 +60,7 @@ abstract contract BatchedClipBreakerSpellTest is DssTest {
ilkReg = IlkRegistryLike(dss.chainlog.getAddress("ILK_REGISTRY"));
clipperMom = ClipperMomLike(dss.chainlog.getAddress("CLIPPER_MOM"));
_setUpSub();
- factory = new BatchedClipBreakerFactory();
+ factory = new GroupedClipBreakerFactory();
spell = DssEmergencySpellLike(factory.deploy(ilks));
stdstore.target(chief).sig("hat()").checked_write(address(spell));
@@ -152,7 +152,7 @@ abstract contract BatchedClipBreakerSpellTest is DssTest {
event SetBreaker(bytes32 indexed ilk, address indexed clip);
}
-contract EthBatchedClipBreakerSpellTest is BatchedClipBreakerSpellTest {
+contract EthGroupedClipBreakerSpellTest is GroupedClipBreakerSpellTest {
function _setUpSub() internal override {
clipA = ClipLike(ilkReg.xlip("ETH-A"));
clipB = ClipLike(ilkReg.xlip("ETH-B"));
@@ -164,11 +164,11 @@ contract EthBatchedClipBreakerSpellTest is BatchedClipBreakerSpellTest {
}
function testDescription() public view {
- assertEq(spell.description(), "Emergency Spell | Batched Clip Breaker: ETH-A, ETH-B, ETH-C");
+ assertEq(spell.description(), "Emergency Spell | Grouped Clip Breaker: ETH-A, ETH-B, ETH-C");
}
}
-contract WstethBatchedClipBreakerSpellTest is BatchedClipBreakerSpellTest {
+contract WstethGroupedClipBreakerSpellTest is GroupedClipBreakerSpellTest {
function _setUpSub() internal override {
clipA = ClipLike(ilkReg.xlip("WSTETH-A"));
clipB = ClipLike(ilkReg.xlip("WSTETH-B"));
@@ -178,11 +178,11 @@ contract WstethBatchedClipBreakerSpellTest is BatchedClipBreakerSpellTest {
}
function testDescription() public view {
- assertEq(spell.description(), "Emergency Spell | Batched Clip Breaker: WSTETH-A, WSTETH-B");
+ assertEq(spell.description(), "Emergency Spell | Grouped Clip Breaker: WSTETH-A, WSTETH-B");
}
}
-contract WbtcBatchedClipBreakerSpellTest is BatchedClipBreakerSpellTest {
+contract WbtcGroupedClipBreakerSpellTest is GroupedClipBreakerSpellTest {
function _setUpSub() internal override {
clipA = ClipLike(ilkReg.xlip("WBTC-A"));
clipB = ClipLike(ilkReg.xlip("WBTC-B"));
@@ -194,6 +194,6 @@ contract WbtcBatchedClipBreakerSpellTest is BatchedClipBreakerSpellTest {
}
function testDescription() public view {
- assertEq(spell.description(), "Emergency Spell | Batched Clip Breaker: WBTC-A, WBTC-B, WBTC-C");
+ assertEq(spell.description(), "Emergency Spell | Grouped Clip Breaker: WBTC-A, WBTC-B, WBTC-C");
}
}
diff --git a/src/line-wipe/BatchedLineWipeSpell.sol b/src/line-wipe/GroupedLineWipeSpell.sol
similarity index 79%
rename from src/line-wipe/BatchedLineWipeSpell.sol
rename to src/line-wipe/GroupedLineWipeSpell.sol
index 2e59ae7..103aa79 100644
--- a/src/line-wipe/BatchedLineWipeSpell.sol
+++ b/src/line-wipe/GroupedLineWipeSpell.sol
@@ -10,7 +10,7 @@
// along with this program. If not, see .
pragma solidity ^0.8.16;
-import {DssBatchedEmergencySpell} from "../DssBatchedEmergencySpell.sol";
+import {DssGroupedEmergencySpell} from "../DssGroupedEmergencySpell.sol";
interface LineMomLike {
function autoLine() external view returns (address);
@@ -34,13 +34,13 @@ interface VatLike {
function wards(address who) external view returns (uint256);
}
-/// @title Emergency Spell: Batched Line Wipe
+/// @title Emergency Spell: Grouped Line Wipe
/// @notice Prevents further debt from being generated for the specified ilks.
/// @custom:authors [amusingaxl]
/// @custom:reviewers []
/// @custom:auditors []
/// @custom:bounties []
-contract BatchedLineWipeSpell is DssBatchedEmergencySpell {
+contract GroupedLineWipeSpell is DssGroupedEmergencySpell {
/// @notice The LineMom from chainlog.
LineMomLike public immutable lineMom = LineMomLike(_log.getAddress("LINE_MOM"));
/// @notice The AutoLine IAM.
@@ -54,15 +54,13 @@ contract BatchedLineWipeSpell is DssBatchedEmergencySpell {
/// @param _ilks The list of ilks for which the spell should be applicable
/// @dev The list size is be at least 2 and less than or equal to 3.
- /// The batched spell is meant to be used for ilks that are a variation of tha same collateral gem
+ /// The grouped spell is meant to be used for ilks that are a variation of tha same collateral gem
/// (i.e.: ETH-A, ETH-B, ETH-C)
- /// There has never been a case where MCD onboarded 4 or more ilks for the same collateral gem.
- /// For cases where there is only one ilk for the same collateral gem, use the single-ilk version.
- constructor(bytes32[] memory _ilks) DssBatchedEmergencySpell(_ilks) {}
+ constructor(bytes32[] memory _ilks) DssGroupedEmergencySpell(_ilks) {}
- /// @inheritdoc DssBatchedEmergencySpell
+ /// @inheritdoc DssGroupedEmergencySpell
function _descriptionPrefix() internal pure override returns (string memory) {
- return "Emergency Spell | Batched Line Wipe:";
+ return "Emergency Spell | Grouped Line Wipe:";
}
/// @notice Wipes the line for the specified ilk..
@@ -85,22 +83,22 @@ contract BatchedLineWipeSpell is DssBatchedEmergencySpell {
}
}
-/// @title Emergency Spell Factory: Batched Line Wipe
-/// @notice On-chain factory to deploy Batched Line Wipe emergency spells.
+/// @title Emergency Spell Factory: Grouped Line Wipe
+/// @notice On-chain factory to deploy Grouped Line Wipe emergency spells.
/// @custom:authors [amusingaxl]
/// @custom:reviewers []
/// @custom:auditors []
/// @custom:bounties []
-contract BatchedLineWipeFactory {
- /// @notice A new BatchedLineWipeSpell has been deployed.
+contract GroupedLineWipeFactory {
+ /// @notice A new GroupedLineWipeSpell has been deployed.
/// @param ilks The list of ilks for which the spell is applicable.
/// @param spell The deployed spell address.
event Deploy(bytes32[] indexed ilks, address spell);
- /// @notice Deploys a BatchedLineWipeSpell contract.
+ /// @notice Deploys a GroupedLineWipeSpell contract.
/// @param ilks The list of ilks for which the spell is applicable.
function deploy(bytes32[] memory ilks) external returns (address spell) {
- spell = address(new BatchedLineWipeSpell(ilks));
+ spell = address(new GroupedLineWipeSpell(ilks));
emit Deploy(ilks, spell);
}
}
diff --git a/src/line-wipe/BatchedLineWipeSpell.t.integration.sol b/src/line-wipe/GroupedLineWipeSpell.t.integration.sol
similarity index 92%
rename from src/line-wipe/BatchedLineWipeSpell.t.integration.sol
rename to src/line-wipe/GroupedLineWipeSpell.t.integration.sol
index 978e450..fe991e6 100644
--- a/src/line-wipe/BatchedLineWipeSpell.t.integration.sol
+++ b/src/line-wipe/GroupedLineWipeSpell.t.integration.sol
@@ -18,7 +18,7 @@ pragma solidity ^0.8.16;
import {stdStorage, StdStorage} from "forge-std/Test.sol";
import {DssTest, DssInstance, MCD} from "dss-test/DssTest.sol";
import {DssEmergencySpellLike} from "../DssEmergencySpell.sol";
-import {BatchedLineWipeSpell, BatchedLineWipeFactory} from "./BatchedLineWipeSpell.sol";
+import {GroupedLineWipeSpell, GroupedLineWipeFactory} from "./GroupedLineWipeSpell.sol";
interface AutoLineLike {
function ilks(bytes32 ilk)
@@ -36,7 +36,7 @@ interface VatLike {
function file(bytes32 ilk, bytes32 what, uint256 data) external;
}
-abstract contract BatchedLineWipeSpellTest is DssTest {
+abstract contract GroupedLineWipeSpellTest is DssTest {
using stdStorage for StdStorage;
address constant CHAINLOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F;
@@ -47,7 +47,7 @@ abstract contract BatchedLineWipeSpellTest is DssTest {
LineMomLike lineMom;
AutoLineLike autoLine;
bytes32[] ilks;
- BatchedLineWipeFactory factory;
+ GroupedLineWipeFactory factory;
DssEmergencySpellLike spell;
function setUp() public {
@@ -61,7 +61,7 @@ abstract contract BatchedLineWipeSpellTest is DssTest {
lineMom = LineMomLike(dss.chainlog.getAddress("LINE_MOM"));
autoLine = AutoLineLike(dss.chainlog.getAddress("MCD_IAM_AUTO_LINE"));
_setUpSub();
- factory = new BatchedLineWipeFactory();
+ factory = new GroupedLineWipeFactory();
spell = DssEmergencySpellLike(factory.deploy(ilks));
stdstore.target(chief).sig("hat()").checked_write(address(spell));
@@ -186,7 +186,7 @@ abstract contract BatchedLineWipeSpellTest is DssTest {
event Wipe(bytes32 indexed ilk);
}
-contract EthBatchedLineWipeSpellTest is BatchedLineWipeSpellTest {
+contract EthGroupedLineWipeSpellTest is GroupedLineWipeSpellTest {
function _setUpSub() internal override {
ilks = new bytes32[](3);
ilks[0] = "ETH-A";
@@ -195,11 +195,11 @@ contract EthBatchedLineWipeSpellTest is BatchedLineWipeSpellTest {
}
function testDescription() public view {
- assertEq(spell.description(), "Emergency Spell | Batched Line Wipe: ETH-A, ETH-B, ETH-C");
+ assertEq(spell.description(), "Emergency Spell | Grouped Line Wipe: ETH-A, ETH-B, ETH-C");
}
}
-contract WstethBatchedLineWipeSpellTest is BatchedLineWipeSpellTest {
+contract WstethGroupedLineWipeSpellTest is GroupedLineWipeSpellTest {
function _setUpSub() internal override {
ilks = new bytes32[](2);
ilks[0] = "WSTETH-A";
@@ -207,11 +207,11 @@ contract WstethBatchedLineWipeSpellTest is BatchedLineWipeSpellTest {
}
function testDescription() public view {
- assertEq(spell.description(), "Emergency Spell | Batched Line Wipe: WSTETH-A, WSTETH-B");
+ assertEq(spell.description(), "Emergency Spell | Grouped Line Wipe: WSTETH-A, WSTETH-B");
}
}
-contract WbtcBatchedLineWipeSpellTest is BatchedLineWipeSpellTest {
+contract WbtcGroupedLineWipeSpellTest is GroupedLineWipeSpellTest {
function _setUpSub() internal override {
ilks = new bytes32[](3);
ilks[0] = "WBTC-A";
@@ -227,6 +227,6 @@ contract WbtcBatchedLineWipeSpellTest is BatchedLineWipeSpellTest {
}
function testDescription() public view {
- assertEq(spell.description(), "Emergency Spell | Batched Line Wipe: WBTC-A, WBTC-B, WBTC-C");
+ assertEq(spell.description(), "Emergency Spell | Grouped Line Wipe: WBTC-A, WBTC-B, WBTC-C");
}
}