Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: RWA Offboarding Checklist #42

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ configs
Crafter
cron
CUs
crypto
DAI
Daiwanese
DAO
Expand Down Expand Up @@ -109,6 +110,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Should we sanity check if the price is reasonable?

Copy link
Contributor Author

@amusingaxl amusingaxl Nov 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's actually a correct way to calculate it. We should probably add it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

* [ ] `bump` `RwaLiquidationOracle` with new computed increased price (`val`)
* [ ] ensure `val` is set accordingly with autoline max debt ceiling (`line`)
* [ ] `val` should enable DAI to be drawn over the loan period while taking into account the configured `ink` amount, interest rate and liquidation ratio (see below)
* [ ] New `val` is calculated with `line * [(1 + duty) ** years] * mat` - rounded up - and makes sense in context of the [rate mechanism](https://github.com/makerdao/developerguides/blob/master/mcd/intro-rate-mechanism/intro-rate-mechanism.md). Minimum duration is usually in the Exec Doc of the spell with the RWAXXX ilk onboarding.
* [ ] Comment explaining `val` formula (`Debt ceiling * [ (1 + RWA stability fee ) ^ (minimum deal duration in years) ] * liquidation ratio`) is present
* [ ] Accompanying comment above `bump` line in format `// XXM * 1.XX^X * X.XX as a WAD` corresponding to the `val` calculation formula (e.g. `// 15M * 1.03^2 * 1.00 as a WAD`) is present along with the calculation formula on the line above
* [ ] IF combining `val` of multiple RWA ilks being combined, `val` calculation is done once per ilk and added to make the total, with workings provided in code comments. The existing `val` value can be retrieved by calling `read()` on `PIP_RWAXX` and converting the result into decimal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check these.

* [ ] `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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been in the spell-reviewer-mainnet-checklist but I'm unsure it was followed in the previous spells.
(eg. soft liquidation for RWA005-A )

Could you guide me where I can find related code or help me understand why this is needed?


## RWA Offboarding Checklist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we require removal from the IlkRegistry here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is that we usually don't remove anything from the ilk registry. I'm not sure if we should do it for this specific case only.


* 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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a situation where the RWA Vault has surplus when being offboarded? In this case, what should be done with it? (send it to surplus buffer?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by surplus? ink > art?

* IF soft liquidation `.tell(ilk)` has **NOT** been called for the ilk in a previous spell:
* [ ] The value of `RwaLiquidationOracle.ilks(ilk).tau` MUST be zero, OTHERWISE the offboarding can only happen in a future spell.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the rest of checklist still happen except RwaLiquidationOracle.cull(ilk, RWAXYZ_A_URN)? (eg. Set Debt ceiling to 0) If then I'd prefer further specify to avoid confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it makes sense. I'll amend this.

* [ ] The debt ceiling (`vat.ilks(ilk).line`) is `0` OR is currently being set to `0`.
* [ ] `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 the stability fee for the ilk is not zero (`jug.ilks(ilk).duty > 1 * RAY`), `jug.drip(ilk)` call is present

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be a case soft liquidation has been called but stability fee for the ilk is not zero?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes... All Centrifuge vaults have non-zero stability fees, and some of them have been put under soft liquidation.

* [ ] `RwaLiquidationOracle.cull(ilk, RWAXYZ_A_URN)` call is present
* OTHERWISE IF there is no more debt remaining in the vault (`vat.urns(ilk, RWAXYZ_A_URN).art == 0`):
* [ ] The debt ceiling (`vat.ilks(ilk).line`) is currently being set to `0`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we deny the Join on the Vat?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RWAs gem joins are permissioned, so in theory there's no harm in leaving the permission there.
We should have a general checklist for "scuttling" contracts (aka the removal of all permissions in the system for a contract) that covers it.


Loading
Loading