Skip to content

[fragmented into !2597, !2599, and !2600] cyclePools IsSyntheticAsset check

This (overgrown) MR has been closed in favour of the more-specific !2597 (merged) and !2599 (closed) (and of lesser importance !2600 (merged)).


[Second edit: Following the edits recorded below, at present I am changing this from Draft to Ready.
Synth buckets will still (for now) exist without being destroyed even if emptied of synths,
but since they are both on-chain (not requiring migrate costs) and only for gas assets I do not feel a pressing need for this to be altered in this Merge Request.]


In POL testing, gavmcd noticed that a Stagenet experimental synth bucket was destroyed for having no RUNE balance.

https://stagenet-thornode.ninerealms.com/thorchain/buckets?height=3685679
Existent.
https://stagenet-thornode.ninerealms.com/thorchain/buckets?height=3685680
Non-existent.
https://stagenet-midgard.ninerealms.com/v2/debug/block/3685680
Suspended.

Draft-relevant point 1: ETH/ETH balance_asset was 107010 before suspension, but the block 3685680 "withdraw" event's emit_asset was 0 and no synths were burnt in a fee-related way. I think this bears further consideration.
[Edit: Following removeLiquidityProviders, this is intended to emit a "withdraw" event with all zeros except for the liquidity units, which in the example match what is expected. While I would like to review the code which handles a bucket's unit calculation/alteration, I am reassured that skipping cyclePools for synth buckets is sufficient to avoid the effect of removeLiquidityProviders, and (at present) this effect a greater reason for skipping.]

Draft-relevant point 2: According to this MR's changes at time of writing, a synth bucket would remain Staged for the entirety of its existence. I do not see a problem with this, but if preferred to be set to Available in its first cyclePools that should be possible.
[Edit: Code now added in addLiquidityV98 to set bucket status to Available on creation.]

Draft-relevant point 3: It seems preferable for a bucket to be deleted when it no longer contains any synth, but the comments on deletion of a normal pool warn the below.

			// check if the rune balance is zero, and asset balance IS NOT
			// zero. This is because we don't want to abandon a pool that is in
			// the process of being created (race condition). We can safely
			// assume, if a pool has asset, but no rune, it should be
			// abandoned.

As I do not know what race condition to lead to a pool otherwise being abandoned in the process of creation (a pending asset state?),
I ask that someone who does know confirm whether such a race condition could happen for a synth bucket (being subject to deletion in the process of being created).
[Edit: As noted for point 1 above, removeLiquidityProviders is designed to emit nothing; if a bucket were to be destroyed using removeLiquidityProviders, care should be taken that this was definitely only done when there were no contained synth that should be withdrawn (or burnt).]
[Third edit: My current impression is that the race condition is if a pool cycle occurs when a pool has a pending Asset or RUNE which has not yet been matched, and so has not yet become BalanceAsset or BalanceRune; buckets I believe are expected to never have a pending coin, being single-sided only.]

Draft-relevant point 4: Though unrelated to point 1, a concern about withdraw amounts:
https://gitlab.com/thorchain/thornode/-/blob/v1.97.2/x/thorchain/withdraw_current.go#L107-108
When a withdraw is from a synth bucket (rather than a Layer 1 pool), calculateVaultWithdrawV1 is used with pool.GetPoolUnits() as the first argument.
GetPoolUnits returns the sum of a pool's/bucket's LPUnits and SynthUnits.
Earlier in withdrawV91, CalcUnits calls CalcUnitsV80, which calculates and sets SynthUnits.
|
My current impression is that this code always treats a synth bucket as having a large amount of SynthUnits (and thus PoolUnits) relative to LPUnits, since referring to the entire SynthSupply of the asset type (whether in the bucket or not).
|
Returning to calculateVaultWithdrawV1, it refers to its first argument as 'vaultUnits' and calculates the asset amount to withdraw with
withdrawAsset := common.GetSafeShare(unitsToClaim, vaultUnits, assetAmt)
, which I currently predict to only withdraw half of what the synth staker is entitled to, since 'unitsToClaim' is calculated from 'lpUnits' (the third argument of calculateVaultWithdrawV1, 'originalLiquidityProviderUnits' in withdrawV91).
|
There is a similar concern for when receiving units for adding liquidity,
namely whether a new staker would receive a disproportionate amount of units relative to previous stakers.
[Second edit: I have now added commits intended to resolve this.]

Edited by Multipartite

Merge request reports