Pre-deployed spells to allow MakerDAO Governance to react faster in case of emergencies.
In Maker's linguo, a spell is a bespoke smart contract to execute authorized actions in Maker Protocol on behalf on Maker Governance.
Since most contracts in Maker Protocol follow a simple, battle-tested authorization scheme, with an "all or nothing" approach, it means that every spell has root access to every single of its components.
In order to mitigate the risks associated with that design decision, the spell process is quite "heavy", where multiple trusted parties are involved, and with comprehensive checklists that must be strictly followed.
With all the complexity and coordination effort, it is not a surprise that it takes a long time for a spell to be successfully crafted, reviewed and handed over to Maker Governance. As per the current process, with the involvement of at least 3 engineers from the different EAs in the Spell Team, not to mention the Governance Facilitators and other key stakeholders, it takes at least 8 working days to deliver a regular spell.
For emergency spells, historically the agreed SLA had been 24h. That was somehow possible when there was a single tight-knit team working on spells, however can be specially challenging with a more decentralized workforce, which is scattered around the world. Even if it was still possible to meet that SLA, in some situations 24h might be too much time.
This repository contains a couple of different spells performing emergency actions that can be pre-deployed to allow MakerDAO Governance to quickly respond to incidents, without the need for dedicated engineers to chime in and craft a bespoke spell in record time.
TBD.
Description | Single ilk | Multi ilk |
---|---|---|
Wipe line |
✅ | ✅ |
Set Clip breaker |
✅ | ✅ |
Disable DDM |
✅ | ❌ |
Stop OSM |
✅ | ✅ |
Halt PSM |
✅ | ❌ |
Stop Splitter |
❌ | ✅ |
No further debt can be generated from an ilk whose line
is wiped.
If MCD_IAM_AUTO_LINE
is configured for the ilk, it will be removed.
It also prevents the debt ceiling (line
) for the affected ilk from being changed without Governance interference.
Halts collateral auctions happening in the MCD_CLIP_{ILK}
contract belonging to the specified ilks. Sets the breaker level to 3
to prevent both kick()
, redo()
and take()
.
Disables a Direct Deposit Module (DIRECT_{ID}_PLAN
), preventing further debt from being generated from it.
Stops the specified Oracle Security Module (PIP_{GEM}
) instances, preventing updates in their price feeds.
Halts swaps on the PSM
, with optional direction (only GEM
buys, only GEM
sells, both).
Disables the smart burn engine.
Emergency spells are meant to be as ABI-compatible with regular spells as possible, to allow Governance to reuse any existing tools, which will not increase the cognitive burden in an emergency situation.
Previous bespoke emergency spells (see example) would perform an open-heart surgery in the
standard DssExec
contract and include the emergency actions calls in the schedule
function. This allows
any contract using the Mom
architecture (see example) to bypass the GSM delay.
The same restrictions to regulars spells still apply (i.e.: storage variables are not allowed).
The emergency spells in this repository build on that idea with a few modifications:
- No
DssExecLib
dependency: emergency actions are quite simple by nature, which makes the use ofDssExecLib
superfluous. - No expiration time: contrary to regular spells, which are meant to be cast only once, emergency spells can be reused if needed, so the expiration time is set so far away in the future that in practice the spell does not expire.
- No separate
DssAction
-like contract: regular spells delegate the execution of specific actions to aDssAction
contract that is deployed by the spell in its constructor. The exact reason for that design choice is unknown to the authors, however we can speculate that the way the spelltag
is derived[1] requires a separate contract. - Casting is a no-op: while bespoke emergency spells would often conflate emergency actions with non-emergency ones,
pre-deployed emergency spells perform only emergency actions, turning
cast()
into a no-op, which exists only for interface-compatibility purposes. - No
MCD_PAUSE
interaction: as its name might suggest, the main goal ofMCD_PAUSE
is to introduce a pause (GSM delay) between the approval of a spell and its execution. Emergency spells by definition bypass the GSM delay, so there is no strong reason toplan
them inMCD_PAUSE
as regular spells.
[1] tag
is meant to be immutable and extract the codehash
of the action
contract. Notice that it would not be possible to get the codehash
of the same contract in its
constructor.
Some types of emergency spells may come in 2 flavors:
- Single ilk: applies the desired spell action for a single pre-defined ilk.
- Multi ilk: applies the desired spell action for all applicable ilks.
Furthermore, this repo provides on-chain factories for single ilk emergency spells to make it easier to deploy for new ilks.
Conforming spells have a done
public storage variable which is false
when the spell is deployed and
set to true
when the spell is cast. This ensures a spell cannot be cast twice.
An emergency spell is not meant to be cast, but it can be scheduled multiple times. So instead of having done
as a
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)
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
case where the system naturally achieves the same final state as the spell being scheduled, in which it would be also
returned true
.
In other words, if done() == true
, it means that the actions performed by the spell are not applicable.