|
| 1 | +# RWA Checklists |
| 2 | + |
| 3 | +## RWA Onboarding Checklist |
| 4 | + |
| 5 | +* [ ] Deployed Contracts |
| 6 | + * [ ] `RwaToken` (Token Used as Collateral In Adapter) |
| 7 | + * [ ] deployed via [`RwaTokenFactory`](https://github.com/makerdao/rwa-toolkit/blob/master/src/tokens/RwaTokenFactory.sol) |
| 8 | + * [ ] Fab matches [chainlog](https://chainlog.makerdao.com/) |
| 9 | + * [ ] 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 |
| 10 | + * [ ] Rwa Token transferred to MCD Pause Proxy |
| 11 | + * [ ] `createRwaToken` parameters are correct |
| 12 | + * [ ] `name` is in `RWA-XYZ` format |
| 13 | + * [ ] `symbol` is in `RWAXYZ` format |
| 14 | + * [ ] `recipient` matches MCD Pause Proxy |
| 15 | + * [ ] `AuthGemJoin` (Join Adapter) |
| 16 | + * [ ] deployed via [JoinFab](https://github.com/makerdao/JoinFab/blob/master/src/JoinFab.sol) |
| 17 | + * [ ] Fab matches [chainlog](https://chainlog.makerdao.com/) |
| 18 | + * [ ] 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) |
| 19 | + * [ ] `newAuthGemJoin` parameters are correct |
| 20 | + * [ ] `owner` matches `PAUSE_PROXY` |
| 21 | + * [ ] `ilk` is the `bytes32` representation of "RWAXYZ-A" |
| 22 | + * [ ] `cast --to-ascii <bytes32>` matches ASCII Ilk |
| 23 | + * [ ] `cast --to-bytes32 $(cast --from-ascii "RWAXYZ-A")` matches `bytes32` (to check the amount of padding zeroes is correct) |
| 24 | + * [ ] `gem` matches `RwaToken` deployed contract |
| 25 | + * [ ] check `wards` |
| 26 | + * [ ] `MCD_PAUSE_PROXY` is relied |
| 27 | + * [ ] deployer is denied |
| 28 | + * [ ] no other address has been relied |
| 29 | + * [ ] `RwaUrn`/`RwaUrn2` |
| 30 | + * [ ] contract is verified on etherscan |
| 31 | + * [ ] ensure `0.6.12` solc version is used |
| 32 | + * [ ] ensure optimizations are off |
| 33 | + * [ ] ensure license is specified (SPDX in code or otherwise) |
| 34 | + * [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/tree/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/urns) and it's consistent with previous RWA onboardings |
| 35 | + * [ ] constructor args are correct and match [Chainlog](https://chainlog.makerdao.com/) |
| 36 | + * [ ] `vat` matches `MCD_VAT` |
| 37 | + * [ ] `jug` matches `MCD_JUG` |
| 38 | + * [ ] `gemJoin` matches `MCD_JOIN_RWAXYZ_A` (Per spell code) |
| 39 | + * [ ] `daiJoin` matches `MCD_JOIN_DAI` |
| 40 | + * [ ] `outputConduit` matches `RwaOutputConduit<2,3>` (Per spell code) |
| 41 | + * [ ] check `wards` |
| 42 | + * [ ] `MCD_PAUSE_PROXY` is relied |
| 43 | + * [ ] deployer is denied |
| 44 | + * [ ] no other address has been relied |
| 45 | + * [ ] `RwaJar` |
| 46 | + * [ ] contract is verified on etherscan |
| 47 | + * [ ] ensure `0.6.12` solc version is used |
| 48 | + * [ ] ensure optimizations are off |
| 49 | + * [ ] ensure license is specified (SPDX in code or otherwise) |
| 50 | + * [ ] 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 |
| 51 | + * [ ] constructor arg matches [`ChainLog`](https://chainlog.makerdao.com/) |
| 52 | + * [ ] `chainlog` |
| 53 | + * [ ] no `wards` |
| 54 | + * [ ] `RwaInputConduit<2>`/`RwaSwapInputConduit<2>` |
| 55 | + * [ ] contract is verified on etherscan |
| 56 | + * [ ] ensure `0.6.12` solc version is used |
| 57 | + * [ ] ensure optimizations are off |
| 58 | + * [ ] ensure license is specified (SPDX in code or otherwise) |
| 59 | + * [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/tree/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/conduits) and it's consistent with previous RWA onboarding |
| 60 | + * [ ] constructor args are correct and match [chainlog](https://chainlog.makerdao.com/) |
| 61 | + * [ ] `dai` |
| 62 | + * [ ] `to` (`RwaUrn`, `RwaJar`) |
| 63 | + * [ ] `gov` (`v1`) |
| 64 | + * [ ] `psm`, `gem` (`v3`) |
| 65 | + * [ ] check `wards` |
| 66 | + * [ ] `MCD_PAUSE_PROXY` is relied |
| 67 | + * [ ] deployer is denied |
| 68 | + * [ ] no other address has been relied |
| 69 | + * [ ] `RwaOutputConduit<2>`/`RwaSwapOutputConduit` |
| 70 | + * [ ] contract is verified on etherscan |
| 71 | + * [ ] ensure `0.6.12` solc version is used |
| 72 | + * [ ] ensure optimizations are off |
| 73 | + * [ ] ensure license is specified (SPDX in code or otherwise) |
| 74 | + * [ ] ensure source matches [GitHub code](https://github.com/makerdao/rwa-toolkit/tree/8d30ed2cb657641253d45b57c894613e26b4ae1b/src/conduits) and it's consistent with previous RWA onboarding |
| 75 | + * [ ] constructor args are correct and match [chainlog](https://chainlog.makerdao.com/) |
| 76 | + * [ ] `dai` |
| 77 | + * [ ] `gov` (`v1`) |
| 78 | + * [ ] `psm`, `gem` (`v3`) |
| 79 | + * [ ] check `wards` |
| 80 | + * [ ] `MCD_PAUSE_PROXY` is relied |
| 81 | + * [ ] deployer is denied |
| 82 | + * [ ] no other address has been relied |
| 83 | + * [ ] Risk Parameters Match Doc |
| 84 | + * [ ] `duty`(stability fee) |
| 85 | + * [ ] `line`(debt ceiling) |
| 86 | + * [ ] `mat` (liquidation ratio) |
| 87 | + * [ ] `val` (oracle price) |
| 88 | + * [ ] `val` is computed as `"debt_ceiling * [ (1 + rwa_stability_fee ) ^ (minimum_deal_duration_in_years) ] * liquidation_ratio"` |
| 89 | + * [ ] `val` matches locally executable formula (e.g. `// bc -l <<< 'scale=18; 50000000 * e(l(1.07) * (3342/365)) * 1.00' | cast --to-wei`) |
| 90 | + * [ ] `tau` (pre-agreed remediation period) |
| 91 | + * [ ] `doc` (IPFS Hash) |
| 92 | + * [ ] Onboarding Actions |
| 93 | + * [ ] `ilk` matches the format `RWAXYZ-A` |
| 94 | + * [ ] Sanity Checks (constructor args, public vars, ... via `require` condition) |
| 95 | + * [ ] `MIP21_LIQUIDATION_ORACLE.init` |
| 96 | + * [ ] `vat.init.ilk` |
| 97 | + * [ ] `jug.init.ilk` (this will set `duty` to `RAY` (zero pct) by default) |
| 98 | + * [ ] `vat` rely `join` |
| 99 | + * [ ] Increase Ilk Debt Ceiling (set DC + increase Global DC) |
| 100 | + * [ ] File Ilk `pip` in the `spotter` |
| 101 | + * [ ] File Ilk `mat` in the `spotter` |
| 102 | + * [ ] Poke `spotter` to pull in the price |
| 103 | + * [ ] `join` rely `urn` |
| 104 | + * [ ] Access Control |
| 105 | + * [ ] `hope` (operator, pause proxy) |
| 106 | + * [ ] `mate` (operator, pause proxy as fallback if required) |
| 107 | + * [ ] `kiss` (whitelist for `urn` destination address `who`) |
| 108 | + * [ ] Fileable (`RwaSwapOutputConduit` and `RwaSwapInputConduit`) |
| 109 | + * [ ] `quitTo` (`file` the appropriate address for conduits per technical assessment) |
| 110 | + * [ ] New Chainlog Entries |
| 111 | + * [ ] `RWAXYZ` |
| 112 | + * [ ] `PIP_RWAXYZ` precomputed via `cast compute-address $MIP21_LIQUIDATION_ORACLE` |
| 113 | + * [ ] Note that a nonce change for `MIP21_LIQUIDATION_ORACLE` prior to casting will cause this to be incorrect |
| 114 | + * [ ] `MCD_JOIN_RWAXYZ_A` |
| 115 | + * [ ] `RWAXYZ_A_URN` |
| 116 | + * [ ] `RWAXYZ_A_JAR` |
| 117 | + * [ ] `RWAXYZ_A_INPUT_CONDUIT` |
| 118 | + * [ ] `RWAXYZ_A_OUTPUT_CONDUIT` |
| 119 | + * [ ] Chainlog Bump |
| 120 | + * [ ] Patch `x.x.1` |
| 121 | + * [ ] Add Ilk to `IlkRegistry` |
| 122 | + * [ ] `put` is used |
| 123 | + * [ ] `class` is 3 |
| 124 | + * [ ] `name` matches forum post (e.g. "RWA007-A: Monetalis Clydesdale") |
| 125 | + * [ ] Ensure `DssExecLib` is used for the Onboarding (e.g. `DssExecLib.vat`) |
| 126 | + * [ ] Test Coverage (Follow Previous Test Patterns) |
| 127 | + * [ ] `testNewChainlogValues` |
| 128 | + * [ ] `testNewIlkRegistryValues` |
| 129 | + * [ ] `testRWAXYZ_INTEGRATION_CONDUITS_SETUP` |
| 130 | + * [ ] `testRWAXYZ_INTEGRATION_BUMP` |
| 131 | + * [ ] `testRWAXYZ_INTEGRATION_TELL` |
| 132 | + * [ ] `testRWAXYZ_INTEGRATION_TELL_CURE_GOOD` |
| 133 | + * [ ] `testFailRWAXYZ_INTEGRATION_CURE_BEFORE_TELL` |
| 134 | + * [ ] `testRWAXYZ_INTEGRATION_TELL_CULL` |
| 135 | + * [ ] `testRWAXYZ_PAUSE_PROXY_OWNS_RWAXYZ_TOKEN_BEFORE_SPELL` |
| 136 | + * [ ] `testRWAXYZ_SPELL_LOCK_OPERATOR_DRAW_WIPE_FREE` |
| 137 | + * [ ] `testFailRWAXYZ_DRAW_ABOVE_LINE` |
| 138 | + * [ ] `testFailRWAXYZ_OUTPUT_CONDUIT_PUSH_ABOVE_BALANCE` |
| 139 | + * [ ] `testRWAXYZ_OPERATOR_LOCK_DRAW_CAGE` |
| 140 | + * [ ] `testRWAXYZ_SPELL_LOCK` |
| 141 | + * [ ] `addresses_<mainnet, goerli>.sol` |
| 142 | + * [ ] `config.sol` |
| 143 | + |
| 144 | +## RWA Update Checklist |
| 145 | + |
| 146 | +* IF `doc` is updated |
| 147 | + * [ ] [`_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` |
| 148 | + * [ ] `_updateDoc(ilk, doc)` is called in the spell |
| 149 | +* IF debt ceiling is updated |
| 150 | + * IF AutoLine update is requested by the Exec Sheet |
| 151 | + * [ ] 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) |
| 152 | + * IF regular debt ceiling (`vat.ilk.line`) update is requested by the Exec Sheet |
| 153 | + * [ ] Collateral type (`ilk`) have [`AutoLine`](https://github.com/makerdao/dss-auto-line/tree/master) disabled previously or in the spell |
| 154 | + * [ ] Debt ceiling (`vat.ilk.line`) is updated, via EITHER: |
| 155 | + * [`DssExecLib.increaseIlkDebtCeiling(ilk, amount, global)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L621C14-L621C36) |
| 156 | + * [`DssExecLib.decreaseIlkDebtCeiling(ilk, amount, global)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L634) |
| 157 | + * [`DssExecLib.setIlkDebtCeiling(ilk, amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L611) |
| 158 | + * [ ] Global debt ceiling (`vat.Line`) is updated accordingly, UNLESS specifically instructed not to, via EITHER: |
| 159 | + * `global` set to `true` in `increaseIlkDebtCeiling`/`decreaseIlkDebtCeiling` |
| 160 | + * [`DssExecLib.setGlobalDebtCeiling(amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L428) |
| 161 | + * [`DssExecLib.increaseGlobalDebtCeiling(amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L436) |
| 162 | + * [`DssExecLib.decreaseGlobalDebtCeiling(amount)`](https://github.com/makerdao/dss-exec-lib/blob/v0.0.9/src/DssExecLib.sol#L445C14-L445C39) |
| 163 | + * [ ] Liquidation oracle price is bumped via `RwaLiquidationOracleLike(MIP21_LIQUIDATION_ORACLE).bump(ilk, val)` pattern |
| 164 | + * [ ] Comment above `bump` explains `val` computation via `// Note: the formula is: "debt_ceiling * [ (1 + rwa_stability_fee ) ^ (minimum_deal_duration_in_years) ] * liquidation_ratio"` |
| 165 | + * [ ] 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`) |
| 166 | + * [ ] The formula matches the example provided above |
| 167 | + * [ ] `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 |
| 168 | + * [ ] `rwa_stability_fee` in the executable formula matches stability fee of the specified RWA found on chain |
| 169 | + * [ ] `minimum_deal_duration_in_years` in the executable formula matches number found in the Exec Sheet of the spell containing relevant RWA onboarding |
| 170 | + * [ ] `liquidation_ratio` in the executable formula matches liquidation ratio of the specified RWA found on chain |
| 171 | + * [ ] Executing formula locally provides integer number that matches the `val` in the spell |
| 172 | + * [ ] `val` makes sense in context of the [rate mechanism](https://github.com/makerdao/developerguides/blob/master/mcd/intro-rate-mechanism/intro-rate-mechanism.md) |
| 173 | + * [ ] 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 |
| 174 | + * [ ] Oracle price is updated via `DssExecLib.updateCollateralPrice(ilk)` |
| 175 | + * 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) |
| 176 | + * [ ] `RwaLiquidationOracle.tell(ilk)` call is present |
| 177 | + * [ ] 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) |
| 178 | + |
| 179 | +## RWA Offboarding Checklist |
| 180 | + |
| 181 | +* [ ] The debt ceiling (`vat.ilks(ilk).line`) is `0` OR is currently being set to `0`. |
| 182 | +* IF soft liquidation `.tell(ilk)` has **NOT** been called for the ilk in a previous spell: |
| 183 | + * [ ] `RwaLiquidationOracle.tell(ilk)` call is present |
| 184 | + * [ ] 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) |
| 185 | +* 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): |
| 186 | + * [ ] Obtain `toc` and `tau` from `RwaLiquidationOracle.ilks(ilk)` |
| 187 | + * [ ] IF `block.timestamp >= toc + tau`, then |
| 188 | + * [ ] IF the stability fee for the ilk is not zero (`jug.ilks(ilk).duty > 1 * RAY`), `jug.drip(ilk)` call is present |
| 189 | + * [ ] `RwaLiquidationOracle.cull(ilk, RWAXYZ_A_URN)` call is present |
| 190 | + * [ ] 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 |
| 191 | + * [ ] OTHERWISE the write-off can only happen in a future spell |
0 commit comments