RWA001 - Verification Process - Third-party

All,

To assist the Trustee (WSFS) in its capacity as verification agent (e.g. the party that will independently verify the blockchain), a minimal* training guide has been assembled to bring them up-to-speed on how the DSS functions at a core level. Most specifically, how to determine the following for a certain vault:

  • Ilk
  • Current Debt Outstanding
  • Current Debt Ceiling
  • Current Interest Rate
  • Liquidation confirmed?
  • Liquidation triggered?

As all sites that make references to current debt outstanding (daistats.com or makerburn.com) are all UI consolidation tools, none of them contemplates liquidations as viewed by a Trustee (as it is totally new!)


As such, it is my plan to forward a link to this Thread to the Trustee once we have some folks from the Smart Contract team confirm the below is an approved method for confirming each of the above.

Ilk

Ilk <—> ASCII (hex to ascii)
Online conversion tools convert the vault name from ascii Text to Hex. The above is an example of RWA001-A. This ILK will never change for RWA001-A

Current Debt Outstanding and Debt Ceiling

Using the ETH smart contract 0x35d1b3f3d7966a1dfe207aa4514c12a259a0492b
—> Then click ilks —> Then input the ilk
0x5257413030312d41000000000000000000000000000000000000000000000000
—> Then take the art / rate / line as outlined below
Current Debt Outstanding (DAI) = art * rate / 10^45
Current Debt Ceiling (DAI) = line / 10^45

Current Interest Rate

Using the ETH smart contract 0x19c0976f590D67707E62397C87829d896Dc0f1F1
—> Then click ilks —> Then input the ilk
0x5257413030312d41000000000000000000000000000000000000000000000000
—> Then (duty / 10^27)^(24*60*60*365)-1 to get the APR

Vault Liquidation Status

{good()}: (GOOD or LIQUIDATED)
Using the ETH smart contract 0x88f88bb9e66241b73b84f3a6e197fbba487b1e30
—> Then click good —> Then input the ilk
0x5257413030312d41000000000000000000000000000000000000000000000000
—> If boolean is True (or 0000000000000000000000000000000000000000000000000000000000000001), then the Vault has NOT been liquidated.
—> If boolean is False (or 0000000000000000000000000000000000000000000000000000000000000000), then the Vault has been liquidated.

Vault Liquidation Triggered

Using the ETH smart contract, 0x88f88bb9e66241b73b84f3a6e197fbba487b1e30
—> Then click ilks —> Then input the ilk
0x5257413030312d41000000000000000000000000000000000000000000000000

If toc is ZERO, a liquidation has NOT been triggered.
If toc is NON-ZERO, a liquidation has been TRIGGERED and countdown to a Liquidation has started.
When NON-ZERO, a cure() transaction must be submitted by MKR governance to return toc back to 0, else vault will be liquidated (Liquidated FALSE or 0000000000000000000000000000000000000000000000000000000000000000).


Verification portal

A verification portal is in the process of being assembled for the Trustee that largely automates all of the above into page to allow for streamlined verification. That said, it is essential that Trustee knows how to verify at the most CORE level directly with a blockchain explorer.

Why does this matter

We are building into the Trust Agreement similar control levers that Maker is already familiar with for crypto based vaults.

For example, by the community reducing the debt ceiling for a given vault, we are building into the legal contracts a covenant and verification that each time a loan is issued (or repaid) that a verification must be completed to ensure that facility is allowed to continue to provide credit. Should that debt ceiling be lower than the debt outstanding, not only will no new loan be allowed, remaining proceeds should be returned. (Precisely the same as Maker operates today with a crypto vault to organically wind down debt exposure).


At this time, I am requesting a review from folks on the Smart Contract team to 100% confirm that I am referencing the correct smart contracts and that the math based on the output of the ILK is correct.

@cmooney @BrianMcMakerDAO @equivrel @hexonaut @Kurt_Barry

Very much appreciated.

8 Likes

This is correct. Validated on the command-line with:

seth --to-ascii "0x5257413030312d41000000000000000000000000000000000000000000000000"
RWA001-A

This works, but isn’t completely accurate. The Art in this case is the entire normalized debt for this ilk. Using this value works in this case because the RWA001-A collateral is specific and authorized. That is, there is only one Vault under this collateral type, meaning you can get away with using the collateral’s overall debt.

seth call $MCD_VAT 'ilks(bytes32)(uint256,uint256,uint256,uint256,uint256)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')")|awk 'NR==1 { print "Art:  " $1 }; NR==2 { print "rate: " $1 };  NR==3 { print "spot: " $1 };  NR==4 { print "line: " $1 };  NR==5 { print "dust: " $1 }; END {}'
Art:  32498834649915
rate: 1003672031925019150805256888
spot: 1060000000000000000000000000000
line: 1000000000000000000000000000000000000000000000000
dust: 0

The more accurate art comes from the urns:

$ seth call $MCD_VAT 'urns(bytes32,address)(uint256,uint256)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')") $RWA001_A_URN|awk 'NR==1 { print "ink:  " $1 }; NR==2 { print "art: " $1 };'
ink:  1000000000000000000
art: 32498834649915

You can see in our case that Art == art; however, for resilience against future constructions where an RWA collateral type may have many different Vaults, I think it would be better to use the art from the second command.

Once one has all these values, the rest of the math does indeed look correct.

rate=$(seth call $MCD_VAT 'ilks(bytes32)(,uint256,,,)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')"))
art=$(seth call $MCD_VAT 'urns(bytes32,address)(,uint256)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')") $RWA001_A_URN)
echo "scale=45; ${art} * ${rate} / 10^45" |bc
.000000000000032498834649915000000000000000000

line=$(seth call $MCD_VAT 'ilks(bytes32)(,,,uint256,)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')"))
echo "scale=45; ${line} / 10^45" |bc
.000000000000000000000000000000032498834649915

Reversing the APY defeated my tooling using the formula you provided, as the exponent was too large; however, the duty is indeed the number we want. I summon @Kurt_Barry or @sctannr to validate your formula.

seth call $MCD_JUG 'ilks(bytes32)(uint256,uint256)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')")|awk 'NR==1 { print "duty: " $1 }; NR==2 { print "rho:  " $1 }; END {}'
duty: 1000000000937303470807876289
rho:  1619208919

I usually take the duty and use a programatic table we’ve put up in IPFS to ensure the per-second rate is correct. You can find the table here. If you search for 1000000000937303470807876289 in that table, you can see it maps to a 3.0% APY, or 300 basis points. If you don’t trust the table, you can run the formula to compute the per-second rate from the command line:

bc -l <<< 'scale=27; e( l(1.03)/(60 * 60 * 24 * 365) )'|sed 's/\.//'
1000000000937303470807876289

And validate the two do indeed match to make a ~3% APY.

This is correct.

seth call $MIP21_LIQUIDATION_ORACLE 'good(bytes32)(bool)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')")
true

Meaning the ilk is good.

This is correct. You can see the values of toc below.

seth call $MIP21_LIQUIDATION_ORACLE 'ilks(bytes32)(string,address,uint48,uint48)' $(seth --to-bytes32 "$(seth --from-ascii 'RWA001-A')")|awk 'NR==1 { print "doc: " $1 }; NR==2 { print "pip: " $1 };  NR==3 { print "tau: " $1 };  NR==4 { print "toc: " $1 }; END {}'
doc: QmdmAUTU3sd9VkdfTZNQM6krc9jsKgF2pz7W1qvvfJo1xk
pip: 0x76A9f30B45F4ebFD60Ce8a1c6e963b1605f7cB6d
tau: 2592000
toc: 0

All addresses you’ve used above are correct. You can find a list of Maker’s mainnet addresses in the changelog.

10 Likes

Chris’s analysis is correct, as far as I can tell. I’ll add a few comments of my own.

Re: Current Debt Outstanding

There’s a further wrinkle which is that if the collateral has not had fee collection triggered recently (via a call to Jug.drip(ilk), the outstanding debt will appear less than than it really is. Not sure how we’re coordinating drips for RWAs. The rho value read from the Jug is the Unix epoch when the last fee collection occurred. Assuming we’re dripping these regularly (e.g. at least daily), the error is small and can probably be disregarded. Might want to document it though. I’m happy to help with developing instructions for doing the correction if needed (including if they’re assessing space for a near-max draw, they should account for the time between the calculation and when the draw actually occurs–eventually this can be built into the dashboard UI).

Re: Current Interest Rate:

  • First, you’ll notice a formatting problem with the equation: 24*60*60 is showing up as 246060. To avoid markdown hiding those asterisks, wrap the expression in backticks–important if this forum post is to be the canonical reference.

  • The formula is correct, although I’d use 10^27 instead of 1000000000000000000000000000 for clarity.

  • The computed value is more accurately called an APY than an APR, I believe (though maybe someone with experience in finance like @equivrel should check me on this).

  • The formula as expressed needs to be evaluated at high precision to avoid significant rounding error, so they should be careful what tool they use to do so. Just pasting (duty / 10^27) ^ (24*60*60*365) - 1 into the Google search bar and hitting enter seems to work sufficiently well, and will be universally available and platform-independent so is likely a good default recommendation. There are alternatives, of course–e.g. the built-in calculator on my Ubuntu installation works, and an online arbitrary-precision calculator can be found at http://apfloat.appspot.com/ , but I’d still just recommend pasting into Google for simplicity.

2 Likes

Updated

Updated


Regarding the comment on the interest rate, they are no verifying that part (and there is no down stream decision making as a result). I do want to demonstrate how they can independently calculate it regardless.


Here is the alpha alpha output for a verification agent (that includes the above instruction integrated) along with computed outputs to compare against. This will of course morph into something that looks far better; however, the essential part for now is the core instruction on how.


As shown on the governance call (and not finalized yet), please see the below decision tree based on these fundamental levers that MKR governance always controls.

2 Likes