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

Enforce reserve amounts amounts strictly positive #290

Merged
merged 5 commits into from
Jan 18, 2024

Conversation

dranov
Copy link
Contributor

@dranov dranov commented Dec 22, 2023

What

This adds a check to the Liquidity Pool deposit method to ensure that both deposited amounts are strictly positive. This ensures the reserves after a (successful) deposit are both strictly positive.

It also adds a check in swap to ensure that the reserves remain strictly positive after a swap.

Why

Without the checks, it is possible to get in a situation where reserve_a > 0 and reserve_b = 0 (or vice-versa). See the test in commit 1338a7c for a scenario that leads to this via deposit. This leads to all further deposits panicking due to a divide-by-zero error on line 241/242. (This only happens if the malfeasant deposit is the first one; if the contract is otherwise properly initialized, things are OK, so this is not very serious.)

A similar thing can happen via swap, as shown by the test in commit 3b1da32.

More generally, though, it seems that the contract is written to assume in several places that reserve_a > 0 && reserve_b > 0 is an appropriate way to check that the contract has been successfully initialised. For instance, this check shows up on L133 and L240. This change actually enforces that assumption.

Known limitations

We came up with these checks whilst formally verifying the Liquidity Pool example contract in this repo.

We have NOT yet established that the property these checks are enforcing (that reserves are both 0 or both strictly positive) is maintained by the withdraw transition. It might be the case that a similar check is necessary there.

@nano-o

For the initial deposit, if one of the deposited token amounts is 0, the
contract can get into a situationw here one of the reserves is 0,
whereas the other is positive. This prevents all further deposits.
See the previous commit for a test case.

The contract is written to assume that `reserve_a > 0 && reserve_b > 0`
after the initial deposit (unless all shares have been withdrawn). For
instance, this assumption shown up in `deposit` when `new_total_shares`
is computed, and also in `get_deposit_amounts`.

This commit actually enforces this invariant.
The same situation in which one reserve is 0 whereas the other is not
(and is positive) can be reached using a `swap`, as this test case
shows. This prevents all further deposits.
Without this, it is possible through a `swap` to prevent all further
deposits. See the previous commit for a test case demonstrating this.
@dranov dranov changed the title Enforce deposit amounts strictly positive Enforce reserve amounts amounts strictly positive Dec 28, 2023
@dranov
Copy link
Contributor Author

dranov commented Dec 28, 2023

I've pushed a new test case that shows the panic issue for all deposits being produced via a swap (rather than via a deposit), and a change to swap that ensures this doesn't happen.

It's not yet clear to me whether a similar check is needed for withdraw.

@nano-o nano-o requested a review from sisuresh January 16, 2024 23:07
Copy link
Contributor

@sisuresh sisuresh left a comment

Choose a reason for hiding this comment

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

Thanks!

@sisuresh sisuresh merged commit b4a2427 into stellar:main Jan 18, 2024
106 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants