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

fix: min fulfillment amount for partial fulfillment #1570

Merged
merged 11 commits into from
Sep 27, 2023

Conversation

wischli
Copy link
Contributor

@wischli wischli commented Sep 26, 2023

Description

This PR mainly fixes issues for partial orderbook fulfillments of foreign investments as a successor of #1559. It also enables partial investments for orders created via extrinsics:

  • Fixes issues for partial swap order fulfillments in pallet-foreign-investments
  • Enables partial swaps for orders created through user extrinsics pallet_order_book::create_order and pallet_order_book::user_update_order which had the min_fulfillment_amount set to the buy_amount making partial fulfillments impossible
  • Removes min_fulfillment_amount from TokenSwaps trait
    • IMO, it should solely be handled by the orderbook
  • Adds NativeBalanceDecimalConverter which provides means of converting between native and asset balance (i.e. re-denomination)
  • Adds MinFulfillmentAmountNative to pallet_order_book::Config which provides a global threshold which gets converted into the incoming asset precision via the also new pallet_order_book::Config::DecimalConverter type

Integration tests

  • Extends FI integration tests to check for correct Executed* dispatches
  • Adds FI integration test for partial order fulfillment in edge case of having an order from pool to foreign as a result of decreasing an investment and collecting a redemption

Checklist:

  • I have added Rust doc comments to structs, enums, traits and functions
  • I have made corresponding changes to the documentation
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or that my feature works

@wischli wischli added I2-bug The code fails to follow expected behaviour. D0-ready Pull request can be merged without special precaution and notification. P7-asap Issue should be addressed in the next days. labels Sep 26, 2023
@wischli wischli self-assigned this Sep 26, 2023
Copy link
Contributor

@lemunozm lemunozm left a comment

Choose a reason for hiding this comment

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

Awesome how fast you're adding new features 🙌🏻. Just a couple of questions, but overall LGTM!

pallets/foreign-investments/src/impls/mod.rs Outdated Show resolved Hide resolved
Comment on lines +509 to +528
fn to_asset_balance(
balance: Balance,
currency_in: CurrencyId,
) -> Result<Balance, DispatchError> {
match currency_in {
CurrencyId::Native => Ok(balance),
CurrencyId::ForeignAsset(_) => {
let to_decimals = AssetRegistry::metadata(&currency_in)
.ok_or(DispatchError::CannotLookup)?
.decimals;
convert_balance_decimals(
cfg_primitives::currency_decimals::NATIVE,
to_decimals,
balance,
)
.map_err(DispatchError::from)
}
_ => Err(DispatchError::Token(sp_runtime::TokenError::Unsupported)),
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Question 1: as I read this method, it seems like I want to transform a currency_in into an asset balance, but the implementation seems to do the opposite, transforming an asset balance to a native one. (Sure, I'm missing something). Is currency_in actually currency_out?

Question 2: Does it make sense to call this method with a native balance? Or should instead be an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. I followed the naming convention from the orderbook and foreign investments such that currency_in refers to the incoming asset for which we want the balance translation. I agree it is not optimal, probably currency_to much better. We could also just remove the direction and call it currency_id. WDYTH?

  2. Since calling it with native balance does not introduce any overhead, I think it should not error out because that makes it more flexible. However, I do not have a strong opinion here.

Copy link
Contributor

@lemunozm lemunozm Sep 27, 2023

Choose a reason for hiding this comment

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

  1. Probably it's me that I feel dyslexic as with right or left 😆. I think I asked about this like 10 times haha. Given that the convention in other places is the same, we can leave it as it is. currency_id also fits 👍🏻

  2. Ok, if semantically makes sense that I could call to_asset_balance() using a native balance expecting no change on it, then I'm fine with the current implementation.

Copy link
Collaborator

@mustermeiszer mustermeiszer left a comment

Choose a reason for hiding this comment

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

That was fast!

Comment on lines +82 to +103
// Order was fulfilled at least for invest swap amount
if status.amount > active_invest_swap_amount {
let invest_swap = SwapOf::<T> {
amount: active_invest_swap_amount,
..status
};
let redeem_swap = SwapOf::<T> {
amount: status.amount.ensure_sub(active_invest_swap_amount)?,
..status
};

// NOTE: Fulfillment of invest swap before redeem one for no particular reason.
// If we wanted to fulfill the min swap amount, we would have to add support for
// oppression of for swap updates to `fulfill_redeem_swap_order` as well in case
// redeem_swap.amount < status.amount < invest_swap.amount
Self::fulfill_invest_swap_order(&info.owner, info.id, invest_swap, false)?;
Self::fulfill_redeem_swap_order(&info.owner, info.id, redeem_swap)
}
// Order was fulfilled below invest swap amount
else {
Self::fulfill_invest_swap_order(&info.owner, info.id, status, true)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do I read this correctly, that we are favouring Investment-swaps over Redepemtion-swaps? I.e. we take care of fulfilling investments first.

Copy link
Contributor Author

@wischli wischli Sep 27, 2023

Choose a reason for hiding this comment

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

Yes. Last night I started refactoring to prioritize lower orders instead, no matter if investment or redemption based. However, this requires adding support for oppressing updating swaps as part of fulfill_redeem_swap_order (i.e. apply_redeem_state_transition) similar to fulfill_invest_swap_order. This is quite tedious and creates more edge cases and should be tested thoroughly. Given that we would like to cut the release ASAP and me feeling confident with the current MVP, I propose to handle this in a subsequent PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

On a note: This favor of investment-swaps only occurs if both the invest state as well as redeem state are swapping into foreign such that the orderbook swap is "sum" of both.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for the context.

@wischli wischli merged commit 828c8b6 into main Sep 27, 2023
9 of 10 checks passed
@wischli wischli mentioned this pull request Sep 27, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
D0-ready Pull request can be merged without special precaution and notification. I2-bug The code fails to follow expected behaviour. P7-asap Issue should be addressed in the next days.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants