[DO NOT MERGE] adds PoC model for vault share price valuation#6434
[DO NOT MERGE] adds PoC model for vault share price valuation#6434Tapanito wants to merge 3 commits intotapanito/lending-fix-amendmentfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## tapanito/lending-fix-amendment #6434 +/- ##
==============================================================
Coverage 79.8% 79.8%
==============================================================
Files 848 848
Lines 67761 67767 +6
Branches 7571 7561 -10
==============================================================
+ Hits 54056 54069 +13
+ Misses 13705 13698 -7 🚀 New features to boost your workflow:
|
ximinez
left a comment
There was a problem hiding this comment.
In addition to the comments below, I noticed there are a lot of places where you have comments describing the current state of the vault. e.g.
// Vault: assetsTotal=1000, omega=50 (loan outstanding), iota=100, sharesTotal=1000
I'd like to see those have actual BEAST_EXPECT checks. Either added, or replacing the comments, up to your judgement.
Partial review. Note to self: left off at testPaperLossThenActualDefault()
|
|
||
| void | ||
| setInterestUnrealized(Number omega) | ||
| borrow(Number const& principal, Number const& interest) |
| XRPL_ASSERT( | ||
| principal > 0 && interest >= 0, | ||
| "xrpl::Vault::borrow requires positive principal and non-negative interest"); | ||
| XRPL_ASSERT( | ||
| principal <= assetsAvailable_, | ||
| "xrpl::Vault::borrow principal exceeds assets available"); |
There was a problem hiding this comment.
Since you're in a test, instead of XRPL_ASSERT, use BEAST_EXPECT, here and in the other tests. And return early if it fails.
There was a problem hiding this comment.
That's a good idea!
There was a problem hiding this comment.
So I'm not sure I can do that, since the Vault has nothing to do with the test suite, and I cannot inherit from it, the best I can do is:
if (!suite_.expect(
principal > 0 && interest >= 0 && (!extraInterest || *extraInterest >= 0),
__FILE__,
__LINE__))
return;
I could move the vault class logic into the test itself, if we really want to replace assertions with beast expect.
| // Deposit 95 assets: shares = floor(95 * 1000 / 950) = floor(100) = 100 | ||
| auto const [shares, assets] = vault.deposit(STAmount{usd, 95}); | ||
| // Deposit 95 assets: shares = floor(95 * 950 / 950) = floor(95) = 95 | ||
| // actualAssets = 95 * 950 / 950 = 95 |
There was a problem hiding this comment.
I have found that writing these kinds of equations out with units really helps as both error checking, and for comprehension. Especially over the long run when this may not be top of mind, and I'm looking at 950 / 950 and wondering "why is this not 1?". So, for this case:
// Deposit 95 assets: shares = floor(95 assets * 950 shares / 950 assets) = floor(95 shares) = 95 shares
// actualAssets = 95 shares * 950 assets / 950 shares = 95 assets
Or to take it a step further, which is probably overkill:
// Deposit 95 assets: shares = floor(95 assets deposited * 950 shares total / 950 net assets) = floor(95 shares deposited) = 95 shares deposited
// actualAssets = 95 shares deposited * 950 net assets / 950 total shares = 95 assets deposited
What do you think?
| auto const out = vault.redeem(STAmount{vault.shareAsset(), 1000}).value(); | ||
| // Approximate bounds: should be within 10% of 0.001 | ||
| BEAST_EXPECT(Number(out) > Number(9, -4)); // > 0.0009 | ||
| BEAST_EXPECT(Number(out) < Number(11, -4)); // < 0.0011 |
There was a problem hiding this comment.
Could you compute this as an exact value? In fact, I would expect this to be the exact amount that was deposited.
auto const expected = ( Number(1, 12) + 1 ) / ( Number(1, 15) + 1000 );
BEAST_EXPECT(expected == Number(1, -3));
BEAST_EXPECT(out == STAmount(usd, expected));
| // withdrawalNAV = 1100 - 100 - 500 = 500 | ||
|
|
||
| // Hard default confirmed (hasPaperLoss=true): | ||
| // assetsTotal -= 500 → 600; omega -= 100 → 0; lossUnrealized -= 500 → 0 |
There was a problem hiding this comment.
| // assetsTotal -= 500 → 600; omega -= 100 → 0; lossUnrealized -= 500 → 0 | |
| // assetsTotal -= 1100 → 600; omega -= 100 → 0; lossUnrealized -= 500 → 0 |
| // Withdraw 0.0001 assets: shares = truncate(0.0001 * 1 / 1) = 0 → tecPRECISION_LOSS | ||
| BEAST_EXPECT(!vault.withdraw(STAmount{usd, 1, -4})); | ||
| BEAST_EXPECT(vault.withdraw(STAmount{usd, 1, -4}).error() == tecPRECISION_LOSS); |
There was a problem hiding this comment.
| // Withdraw 0.0001 assets: shares = truncate(0.0001 * 1 / 1) = 0 → tecPRECISION_LOSS | |
| BEAST_EXPECT(!vault.withdraw(STAmount{usd, 1, -4})); | |
| BEAST_EXPECT(vault.withdraw(STAmount{usd, 1, -4}).error() == tecPRECISION_LOSS); | |
| // Withdraw 0.0001 assets: shares = truncate(0.0001 * 1 / 1) = 0 → tecPRECISION_LOSS | |
| auto const withdrawResult = vault.withdraw(STAmount{usd, 1, -4}); | |
| BEAST_EXPECT(!withdrawResult); | |
| BEAST_EXPECT(withdrawResult.error() == tecPRECISION_LOSS); |
| auto const ok = vault.redeem(STAmount{vault.shareAsset(), 200}); | ||
| BEAST_EXPECT(ok.has_value()); | ||
| BEAST_EXPECT(Number(ok.value()) == Number(200)); | ||
| } |
There was a problem hiding this comment.
At this point assetsAvailable is 0, correct? Is it fair to allow one holder to remove all the available assets, and force everyone else to wait for the loan to be paid back (and hope it doesn't default)?
| { | ||
| return STAmount{shareAsset_, sharesTotal_}; | ||
| } | ||
|
|
There was a problem hiding this comment.
I think it would be worth it to add STAmount depositNAV() const and STAmount withdrawNAV() const function. The functions could be used by depost() and withdraw(), but they could also be used in the tests where right now you have comments saying what it should be.
Spec: XRPLF/XRPL-Standards#485
High Level Overview of Change
Context of Change
Type of Change
.gitignore, formatting, dropping support for older tooling)API Impact
libxrplchange (any change that may affectlibxrplor dependents oflibxrpl)