Skip to content

Commit

Permalink
Merge pull request #42 from makerdao/feat/rwa-offboarding
Browse files Browse the repository at this point in the history
Feat: RWA Offboarding Checklist
  • Loading branch information
amusingaxl authored Dec 11, 2024
2 parents 424c561 + 22588cc commit 042effd
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 171 deletions.
2 changes: 2 additions & 0 deletions .wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Crafter
Crafter's
cron
CUs
crypto
DAI
Daiwanese
DAO
Expand Down Expand Up @@ -110,6 +111,7 @@ repos
RPC
RWA
RWAXXX
RWAXYZ
setIlkAutoLineDebtCeiling
setIlkAutoLineParameters
setIlkDebtCeiling
Expand Down
191 changes: 191 additions & 0 deletions spell/rwa-checklists.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# RWA Checklists

## RWA Onboarding Checklist

* [ ] Deployed Contracts
* [ ] `RwaToken` (Token Used as Collateral In Adapter)
* [ ] deployed via [`RwaTokenFactory`](https://github.com/makerdao/rwa-toolkit/blob/master/src/tokens/RwaTokenFactory.sol)
* [ ] Fab matches [chainlog](https://chainlog.makerdao.com/)
* [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/blob/92c79aac24ef7645902ce4be57ba41b19e6c7dd5/src/tokens/RwaToken.sol) and it's consistent with previous RWA onboarding
* [ ] Rwa Token transferred to MCD Pause Proxy
* [ ] `createRwaToken` parameters are correct
* [ ] `name` is in `RWA-XYZ` format
* [ ] `symbol` is in `RWAXYZ` format
* [ ] `recipient` matches MCD Pause Proxy
* [ ] `AuthGemJoin` (Join Adapter)
* [ ] deployed via [JoinFab](https://github.com/makerdao/JoinFab/blob/master/src/JoinFab.sol)
* [ ] Fab matches [chainlog](https://chainlog.makerdao.com/)
* [ ] ensure source matches [GitHub code](https://github.com/makerdao/dss-gem-joins/blob/8ca0a7fdd5edc6ed3da68c3ffdfadfb9540c83f7/src/join-auth.sol) and it's consistent with previous RWA onboarding (NOTE: Etherscan may have a bug where it displays additional code for `AuthGemJoin`. In this case, using `cast interface` or otherwise, ensure that this code cannot be executed)
* [ ] `newAuthGemJoin` parameters are correct
* [ ] `owner` matches `PAUSE_PROXY`
* [ ] `ilk` is the `bytes32` representation of "RWAXYZ-A"
* [ ] `cast --to-ascii <bytes32>` matches ASCII Ilk
* [ ] `cast --to-bytes32 $(cast --from-ascii "RWAXYZ-A")` matches `bytes32` (to check the amount of padding zeroes is correct)
* [ ] `gem` matches `RwaToken` deployed contract
* [ ] check `wards`
* [ ] `MCD_PAUSE_PROXY` is relied
* [ ] deployer is denied
* [ ] no other address has been relied
* [ ] `RwaUrn`/`RwaUrn2`
* [ ] contract is verified on etherscan
* [ ] ensure `0.6.12` solc version is used
* [ ] ensure optimizations are off
* [ ] ensure license is specified (SPDX in code or otherwise)
* [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/tree/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/urns) and it's consistent with previous RWA onboardings
* [ ] constructor args are correct and match [Chainlog](https://chainlog.makerdao.com/)
* [ ] `vat` matches `MCD_VAT`
* [ ] `jug` matches `MCD_JUG`
* [ ] `gemJoin` matches `MCD_JOIN_RWAXYZ_A` (Per spell code)
* [ ] `daiJoin` matches `MCD_JOIN_DAI`
* [ ] `outputConduit` matches `RwaOutputConduit<2,3>` (Per spell code)
* [ ] check `wards`
* [ ] `MCD_PAUSE_PROXY` is relied
* [ ] deployer is denied
* [ ] no other address has been relied
* [ ] `RwaJar`
* [ ] contract is verified on etherscan
* [ ] ensure `0.6.12` solc version is used
* [ ] ensure optimizations are off
* [ ] ensure license is specified (SPDX in code or otherwise)
* [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/blob/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/jars/RwaJar.sol) and it's consistent with previous RWA onboarding
* [ ] constructor arg matches [`ChainLog`](https://chainlog.makerdao.com/)
* [ ] `chainlog`
* [ ] no `wards`
* [ ] `RwaInputConduit<2>`/`RwaSwapInputConduit<2>`
* [ ] contract is verified on etherscan
* [ ] ensure `0.6.12` solc version is used
* [ ] ensure optimizations are off
* [ ] ensure license is specified (SPDX in code or otherwise)
* [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/tree/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/conduits) and it's consistent with previous RWA onboarding
* [ ] constructor args are correct and match [chainlog](https://chainlog.makerdao.com/)
* [ ] `dai`
* [ ] `to` (`RwaUrn`, `RwaJar`)
* [ ] `gov` (`v1`)
* [ ] `psm`, `gem` (`v3`)
* [ ] check `wards`
* [ ] `MCD_PAUSE_PROXY` is relied
* [ ] deployer is denied
* [ ] no other address has been relied
* [ ] `RwaOutputConduit<2>`/`RwaSwapOutputConduit`
* [ ] contract is verified on etherscan
* [ ] ensure `0.6.12` solc version is used
* [ ] ensure optimizations are off
* [ ] ensure license is specified (SPDX in code or otherwise)
* [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/tree/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/conduits) and it's consistent with previous RWA onboarding
* [ ] constructor args are correct and match [chainlog](https://chainlog.makerdao.com/)
* [ ] `dai`
* [ ] `gov` (`v1`)
* [ ] `psm`, `gem` (`v3`)
* [ ] check `wards`
* [ ] `MCD_PAUSE_PROXY` is relied
* [ ] deployer is denied
* [ ] no other address has been relied
* [ ] Risk Parameters Match Doc
* [ ] `duty`(stability fee)
* [ ] `line`(debt ceiling)
* [ ] `mat` (liquidation ratio)
* [ ] `val` (oracle price)
* [ ] `val` is computed as `"debt_ceiling * [ (1 + rwa_stability_fee ) ^ (minimum_deal_duration_in_years) ] * liquidation_ratio"`
* [ ] `val` matches locally executable formula (e.g. `// bc -l <<< 'scale=18; 50000000 * e(l(1.07) * (3342/365)) * 1.00' | cast --to-wei`)
* [ ] `tau` (pre-agreed remediation period)
* [ ] `doc` (IPFS Hash)
* [ ] Onboarding Actions
* [ ] `ilk` matches the format `RWAXYZ-A`
* [ ] Sanity Checks (constructor args, public vars, ... via `require` condition)
* [ ] `MIP21_LIQUIDATION_ORACLE.init`
* [ ] `vat.init.ilk`
* [ ] `jug.init.ilk` (this will set `duty` to `RAY` (zero pct) by default)
* [ ] `vat` rely `join`
* [ ] Increase Ilk Debt Ceiling (set DC + increase Global DC)
* [ ] File Ilk `pip` in the `spotter`
* [ ] File Ilk `mat` in the `spotter`
* [ ] Poke `spotter` to pull in the price
* [ ] `join` rely `urn`
* [ ] Access Control
* [ ] `hope` (operator, pause proxy)
* [ ] `mate` (operator, pause proxy as fallback if required)
* [ ] `kiss` (whitelist for `urn` destination address `who`)
* [ ] Fileable (`RwaSwapOutputConduit` and `RwaSwapInputConduit`)
* [ ] `quitTo` (`file` the appropriate address for conduits per technical assessment)
* [ ] New Chainlog Entries
* [ ] `RWAXYZ`
* [ ] `PIP_RWAXYZ` precomputed via `cast compute-address $MIP21_LIQUIDATION_ORACLE`
* [ ] Note that a nonce change for `MIP21_LIQUIDATION_ORACLE` prior to casting will cause this to be incorrect
* [ ] `MCD_JOIN_RWAXYZ_A`
* [ ] `RWAXYZ_A_URN`
* [ ] `RWAXYZ_A_JAR`
* [ ] `RWAXYZ_A_INPUT_CONDUIT`
* [ ] `RWAXYZ_A_OUTPUT_CONDUIT`
* [ ] Chainlog Bump
* [ ] Patch `x.x.1`
* [ ] Add Ilk to `IlkRegistry`
* [ ] `put` is used
* [ ] `class` is 3
* [ ] `name` matches forum post (e.g. "RWA007-A: Monetalis Clydesdale")
* [ ] Ensure `DssExecLib` is used for the Onboarding (e.g. `DssExecLib.vat`)
* [ ] Test Coverage (Follow Previous Test Patterns)
* [ ] `testNewChainlogValues`
* [ ] `testNewIlkRegistryValues`
* [ ] `testRWAXYZ_INTEGRATION_CONDUITS_SETUP`
* [ ] `testRWAXYZ_INTEGRATION_BUMP`
* [ ] `testRWAXYZ_INTEGRATION_TELL`
* [ ] `testRWAXYZ_INTEGRATION_TELL_CURE_GOOD`
* [ ] `testFailRWAXYZ_INTEGRATION_CURE_BEFORE_TELL`
* [ ] `testRWAXYZ_INTEGRATION_TELL_CULL`
* [ ] `testRWAXYZ_PAUSE_PROXY_OWNS_RWAXYZ_TOKEN_BEFORE_SPELL`
* [ ] `testRWAXYZ_SPELL_LOCK_OPERATOR_DRAW_WIPE_FREE`
* [ ] `testFailRWAXYZ_DRAW_ABOVE_LINE`
* [ ] `testFailRWAXYZ_OUTPUT_CONDUIT_PUSH_ABOVE_BALANCE`
* [ ] `testRWAXYZ_OPERATOR_LOCK_DRAW_CAGE`
* [ ] `testRWAXYZ_SPELL_LOCK`
* [ ] `addresses_<mainnet, goerli>.sol`
* [ ] `config.sol`

## RWA Update Checklist

* IF `doc` is updated
* [ ] [`_updateDoc` helper](https://github.com/makerdao/spells-mainnet/blob/7400e91c4f211fc24bd4d3a95a86416afc4df9d1/archive/2023-09-27-DssSpell/DssSpell.sol#L76-L87) is copied one-to-one from the archive and defined above `actions`
* [ ] `_updateDoc(ilk, doc)` is called in the spell
* IF debt ceiling is updated
* IF AutoLine update is requested by the Exec Sheet
* [ ] Parameters are set via [`DssExecLib.setIlkAutoLineParameters(ilk, amount, gap, ttl)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L648) or [`DssExecLib.setIlkAutoLineDebtCeiling(ilk, amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L658)
* IF regular debt ceiling (`vat.ilk.line`) update is requested by the Exec Sheet
* [ ] Collateral type (`ilk`) have [`AutoLine`](https://github.com/makerdao/dss-auto-line/tree/master) disabled previously or in the spell
* [ ] Debt ceiling (`vat.ilk.line`) is updated, via EITHER:
* [`DssExecLib.increaseIlkDebtCeiling(ilk, amount, global)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L621C14-L621C36)
* [`DssExecLib.decreaseIlkDebtCeiling(ilk, amount, global)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L634)
* [`DssExecLib.setIlkDebtCeiling(ilk, amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L611)
* [ ] Global debt ceiling (`vat.Line`) is updated accordingly, UNLESS specifically instructed not to, via EITHER:
* `global` set to `true` in `increaseIlkDebtCeiling`/`decreaseIlkDebtCeiling`
* [`DssExecLib.setGlobalDebtCeiling(amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L428)
* [`DssExecLib.increaseGlobalDebtCeiling(amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L436)
* [`DssExecLib.decreaseGlobalDebtCeiling(amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L445C14-L445C39)
* [ ] Liquidation oracle price is bumped via `RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).bump(ilk, val)` pattern
* [ ] Comment above `bump` explains `val` computation via `// Note: the formula is: "debt_ceiling * [ (1 + rwa_stability_fee ) ^ (minimum_deal_duration_in_years) ] * liquidation_ratio"`
* [ ] Comment above `bump` provides locally executable formula (e.g. `// bc -l <<< 'scale=18; 50000000 * e(l(1.07) * (3342/365)) * 1.00' | cast --to-wei`)
* [ ] The formula matches the example provided above
* [ ] `debt_ceiling` in the executable formula matches new debt ceiling set in the spell or the maximum possible debt ceiling in case of the enabled AutoLine
* [ ] `rwa_stability_fee` in the executable formula matches stability fee of the specified RWA found on chain
* [ ] `minimum_deal_duration_in_years` in the executable formula matches number found in the Exec Sheet of the spell containing relevant RWA onboarding
* [ ] `liquidation_ratio` in the executable formula matches liquidation ratio of the specified RWA found on chain
* [ ] Executing formula locally provides integer number that matches the `val` in the spell
* [ ] `val` makes sense in context of the [rate mechanism](https://github.com/makerdao/developerguides/blob/master/mcd/intro-rate-mechanism/intro-rate-mechanism.md)
* [ ] IF multiple RWA ilks are being combined into one, `val` calculation is done once per ilk and added to make the total, with separate executable formulas provided in comments. The existing `val` value can be retrieved by calling `read()` on `PIP_RWAXYZ` and converting the result into decimal
* [ ] Oracle price is updated via `DssExecLib.updateCollateralPrice(ilk)`
* IF soft liquidation explicitly requested to be triggered (via `.tell(ilk)`) AND debt ceiling (`vat.ilks(ilk).line`) is `0` (OR is being set to `0` in the current spell)
* [ ] `RwaLiquidationOracle.tell(ilk)` call is present
* [ ] IF `RWAXYZ_A_INPUT_CONDUIT` is an instance of [`TinlakeMgr`](https://github.com/centrifuge/tinlake-maker-lib/blob/master/src/mgr.sol) (it is a Centrifuge integration), additional `TinlakeMgr.tell()` call is present (in order to prevent further `TIN` redemptions in the Centrifuge pool)

## RWA Offboarding Checklist

* [ ] The debt ceiling (`vat.ilks(ilk).line`) is `0` OR is currently being set to `0`.
* IF soft liquidation `.tell(ilk)` has **NOT** been called for the ilk in a previous spell:
* [ ] `RwaLiquidationOracle.tell(ilk)` call is present
* [ ] IF `RWAXYZ_A_INPUT_CONDUIT` is an instance of [`TinlakeMgr`](https://github.com/centrifuge/tinlake-maker-lib/blob/master/src/mgr.sol) (it is a Centrifuge integration), additional `TinlakeMgr.tell()` call is present (in order to prevent further `TIN` redemptions in the Centrifuge pool)
* IF there is debt in the RWA Vault (`vat.urns(ilk, RWAXYZ_A_URN).art > 0`), proceed with the write-off (i.e.: vault is in default):
* [ ] Obtain `toc` and `tau` from `RwaLiquidationOracle.ilks(ilk)`
* [ ] IF `block.timestamp >= toc + tau`, then
* [ ] IF the stability fee for the ilk is not zero (`jug.ilks(ilk).duty > 1 * RAY`), `jug.drip(ilk)` call is present
* [ ] `RwaLiquidationOracle.cull(ilk, RWAXYZ_A_URN)` call is present
* [ ] IF `RWAXYZ_A_INPUT_CONDUIT` is an instance of [`TinlakeMgr`](https://github.com/centrifuge/tinlake-maker-lib/blob/master/src/mgr.sol) (it is a Centrifuge integration), additional `TinlakeMgr.cull()` call is present
* [ ] OTHERWISE the write-off can only happen in a future spell
Loading

0 comments on commit 042effd

Please sign in to comment.