-
Notifications
You must be signed in to change notification settings - Fork 78
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
Merge investor into TOCC #525
Conversation
This expands `close_epoch` to have most of the top-level epoch closing logic, with most of the meat still stubbed out.
These extrinsics are really an interface to do fake borrowing/payback until we have a borrower side to interact with. They are renamed to indicate now that that is what they do.
This removes some confusing code where the terms `pool` or `tranche` were being used to refer to the id in some cases but the struct data in others. IDs are now always delimited as such
* Add Reserve * wip: checkpoint epoch validation * checkpoint - sub ratio validation * checkpoint - return errors + simplify balance to perquintil conversion * address comments 1 * address comments 2 * moved currency/tranchetoken as primitive crate
* Integrates crowdloan pallets to altait * Pump rt-version 1005, minDep democ 1000 AIR
…e#474) * Changed validate-unsigned The changes to the validate unsigned are here to reflect more detailed error messages at failure with the costum error instead of the misleading 'BadProof' return value. Furthermore, this fixes an issue, where somebody could have a signature of any parachain-relay-chain account and then use a proof of any other relay-chain contribution to gain those rewards. * Enable claim_reward calls * Remove indicator for claim failures
* Epoch execution phase 1 This is the beginning of epoch execution. It updates tranche state and stores the execution results, but since token pricing is not yet implemented it cannot do rebalancing or other bits like that. * Epoch close pricing calculation This now calculates a price (including dripping interest) for the tranches at epoch close. There are other locations where dripping interest needs to occur, to come in further commits. * Store additional state at epoch close In addition to the per-tranche supply/redeem targets for an epoch, we now also store the nav, reserve, per-tranche price, and per-tranche total value at the time of close. * Update epoch validation tests for new epoch storage model * Implement tranche rebalancing during epoch execution This also includes a new `fake_nav` to make testing easier * Track tranche debt/balance amounts in borrow/repay fns * Account for updated tranche value in epoch validity * Fixes for epoch execution / rebalancing * Epoch execution testing * Use a less-bad pow() impl for calculating interest * Avoid rounding issues when round-tripping between currencies
Things left to do:
|
This comment has been minimized.
This comment has been minimized.
0c951cf
to
8f3dc69
Compare
@branan there are some merge conflicts; and is this PR ready for review? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some questions on the tranche balancing
|
||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] | ||
pub struct Tranche<Balance> { | ||
pub interest_per_sec: Perquintill, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any specific reason why we are not using substrate fixed point types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this needs to be using 27 precision instead of 18
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perquintill is a fixed point type, technically. It's the semantically-correct type for a number which cannot exceed 1.0.
This only stores the base interest rate and is not used as an accumulator. Intermediate values for interest calculations do use 27 decimals. I think 18 decimals is sufficient here, but if we really want to store 27 we should make a Peroctill
type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use the 27 precision
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fine. I'll add an item to the things-to-do in December to add a Peroctill
we can use for 27-decimal proper fractions and update this. Should be a one-liner in our substrate fork and here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this mean we will have to use the fork of substrate again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're already still using a fork for the other 27-digit fixed points, right? Or did we finally get that upstream?
I may actually use Fixed27 instead of Peroctill, so that the interest is in the form of 1.<rate>
. it saves one addition for every interest calculation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We ware using the main repo on parachain at least. Would prefer to keep it that way 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We dont use the fork anymore. I have moved the macro to our repo. You can already use the macro from runtime-common
@@ -0,0 +1,49 @@ | |||
[package] | |||
authors = ['Substrate DevHub <https://github.com/substrate-developer-hub>'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this Cargo toml needs an update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, still copied from the template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do a separate PR doing an update here as well?
) -> DispatchResult { | ||
let owner = ensure_signed(origin)?; | ||
|
||
// TODO: Ensure owner is authorized to create a pool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if this is still valid
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this gets lifted out into the pool pallet now, I believe
.map_err(|_| Error::<T>::TrancheId)?, | ||
}; | ||
Self::update_tranche_for_epoch( | ||
loc, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have to handle the execution failure so that we have an way to close it through a call
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update_tranche_for_epoch
is infallible here, since it can only fail on transfers and has no transfers to make. I can leave a comment to that effect (or add a .expect()
)
tranche_id: T::TrancheId::try_from(tranche_id) | ||
.map_err(|_| Error::<T>::TrancheId)?, | ||
}; | ||
Self::update_tranche_for_epoch( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should handle the failed case down the line for theese storage changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here it probably makes sense to catch that the transfer failed and fail cleanly in one place, with the pool marked as "broken" somehow to prevent further epoch operations until we can fix it with sudo
somehow.
That's a big enough change it probably deserves it's own PR separately from the merge work?
tranche.debt = remaining_nav; | ||
tranche.reserve = remaining_reserve; | ||
} else { | ||
tranche.debt = ratio.mul_ceil(nav); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn;t this be the debtratio instead of tranch share of the pool ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't track separate debt and reserve ratios. We track a single pool ratio, and the goal of this step is to readjust the debt/reserve values of each tranche based on the new debt/reserve totals and the tranche's recomputed ratio from the epoch close.
@NunoAlexandre Just needs a rebase on the last couple commits from the borrower benchmarking, it's otherwise ready to go |
Do we have a spec this PR is implementing that I can look to for a basis of review? |
@NunoAlexandre The point of this PR was really just the merge, which doesn't have its own standalone spec. It is, however, a convenient place for folks that haven't had eyes on the lender side to comment on things. The overall lender spec is at https://centrifuge.hackmd.io/l1HoQDTUSHKDO8-HbD0NaQ, and the original Tinlake components are the |
I'm trying not to clutter this PR with changes to the underlying Lender work right now, since the goal here is to get everything in one branch to make continued development more straightforward. I'd like to see this get through once the merge part is unobjectionable, and issues can be filed to fix up anything that folks find while going over this. |
@branan it is fine to merge as is but I would suggest we add these relevent issue as either todo(s), or actual issues that we can actively track. Also helps us to what to pick immediately next |
Yes, will absolutely file real tickets to track it all. I'll resolve the merge conflicts momentarily and get things ticketed out this afternoon. |
8f3dc69
to
5b09f5e
Compare
This is re-re-based on top of the TOCC branch with the updates from the final borrower benchmarking PR |
@branan okay, merge this up when you are ready. We can talk next steps in sync then :-D |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bit late, but regarding the some important things I wanted to remark here.
- if: matrix.target == 'build-runtime' | ||
name: Setup - gcloud / gsutil | ||
uses: google-github-actions/setup-gcloud@master | ||
with: | ||
service_account_key: ${{ secrets.GCS_SA_KEY }} | ||
project_id: ${{ secrets.GCS_PROJECT }} | ||
export_default_credentials: true | ||
- if: matrix.target == 'build-runtime' | ||
name: Publish to GCS | ||
run: | | ||
gsutil cp ./runtime/altair/target/srtool/release/wbuild/altair-runtime/altair_runtime.compact.wasm gs://centrifuge-artifact-releases/parachain/altair_runtime-$(git rev-parse --short HEAD).compact.wasm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where and why do we store the wasms now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think @mikiquantum wrote this originally? I'm not sure why we decided to push things to google storage.
|
||
#[derive(Clone, Encode, Decode, Eq, PartialEq, RuntimeDebug, Default)] | ||
pub struct Tranche<Balance> { | ||
pub interest_per_sec: Perquintill, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this mean we will have to use the fork of substrate again?
Order::<T>::try_mutate(&tranche, &who, |order| -> DispatchResult { | ||
if amount > order.redeem { | ||
let transfer_amount = amount - order.redeem; | ||
Pool::<T>::try_mutate(pool_id, |pool| { | ||
let pool = pool.as_mut().ok_or(Error::<T>::NoSuchPool)?; | ||
let epoch_redeem = &mut pool.tranches[tranche_id.into()].epoch_redeem; | ||
*epoch_redeem = epoch_redeem | ||
.checked_add(&transfer_amount) | ||
.ok_or(Error::<T>::Overflow)?; | ||
T::Tokens::transfer(currency, &who, &pool_account, transfer_amount) | ||
})?; | ||
} else if amount < order.redeem { | ||
let transfer_amount = order.redeem - amount; | ||
Pool::<T>::try_mutate(pool_id, |pool| { | ||
let pool = pool.as_mut().ok_or(Error::<T>::NoSuchPool)?; | ||
let epoch_redeem = &mut pool.tranches[tranche_id.into()].epoch_redeem; | ||
*epoch_redeem = epoch_redeem | ||
.checked_sub(&transfer_amount) | ||
.ok_or(Error::<T>::Overflow)?; | ||
T::Tokens::transfer(currency, &pool_account, &who, transfer_amount) | ||
})?; | ||
} | ||
order.redeem = amount; | ||
order.epoch = epoch; | ||
Ok(()) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frontrunning as mentioned above.
// If closing the epoch would wipe out a tranche, the close is invalid. | ||
// TODO: This should instead put the pool into an error state | ||
ensure!( | ||
!epoch_tranche_prices | ||
.iter() | ||
.any(|price| *price == Zero::zero()), | ||
Error::<T>::WipedOut | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When does this potentially happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should only happen if the NAV has dropped precipitously (due to defaults or something like that)
let pool_address = PoolLocator { | ||
pool_id: loc.pool_id, | ||
} | ||
.into_account(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment on PoolLocatpr
above.
pool_id: T::PoolId, | ||
amount: T::Balance, | ||
) -> DispatchResult { | ||
let pool_account = PoolLocator { pool_id }.into_account(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment on PoolLocator
above.
No description provided.