Bonfida/dex-v4

Bug when processing Event::Out in consume events

Closed this issue · 4 comments

Could make this as a pull request but probably simpler to post the solution here and let you guys add the fix when convenient. It doesn't look like a loss of funds issue but it definitely could eventually brick someone's account if their locked token accounts hit u64::max.

Side::Ask => {
user_account.header.base_token_free = user_account
.header
.base_token_free
.checked_add(base_size)
.unwrap()
}
Side::Bid => {
let price = (order_id >> 64) as u64;
let qty_to_transfer = fp32_mul(base_size, price);
user_account.header.quote_token_free = user_account
.header
.quote_token_free
.checked_add(qty_to_transfer.unwrap())
.unwrap();
}

Consume events function only increases token_free values, it never reduces the token_locked values. Essentially you're missing quote_token_locked.checked_sub and base_token_locked.checked_sub.

Compare with how these values are updated in the cancel orders

Side::Bid => {
user_account.header.quote_token_free = user_account
.header
.quote_token_free
.checked_add(order_summary.total_quote_qty)
.unwrap();
user_account.header.quote_token_locked = user_account
.header
.quote_token_locked
.checked_sub(order_summary.total_quote_qty)
.unwrap();
}
Side::Ask => {
user_account.header.base_token_free = user_account
.header
.base_token_free
.checked_add(order_summary.total_base_qty)
.unwrap();
user_account.header.base_token_locked = user_account
.header
.base_token_locked
.checked_sub(order_summary.total_base_qty)
.unwrap();
}

Hi @Henry-E! Thanks for reporting this. I agree with the fact that quote_token_locked isn't behaving as it should. We'll definitely fix this because this field might be useful down the line. However, I think that account bricking is a non-issue in this context. This is because we already store lifetime market volume as a u64, because we consider implicitly that a u64 is large enough. In this context, we still have quote_token_free << lifetime_market_volume. To give an idea for this, a volume of u64::MAX USDC would be around 18 trillion dollars.

Ok but it's still definitely doing incorrect maths!

We are in agreement, but since the field is non-critical and doesn't affect the business logic, and the unwrap case you outlined above is basically unreachable, this is a non-critical bug. We're definitely fixing it though, implementations composing with Serum might make use of this field.