bug: handling token boundaries + invariant
Opened this issue · 1 comments
Issue
I'll do my best to explain here, but what I've found in the the portfolio_simulations shows that we have a massive spike in the invariant as the tokens approach their boundary values. We first see it in the WARN
level logs that Portfolio is rejecting the output amount and we loop to reduce the output size by enough:
[2023-09-01T17:52:25Z WARN portfolio_simulation::strategies] Swap failed due to revert: Portfolio_InvalidInvariant(Portfolio_InvalidInvariant { prev: 6162663215956134642, next: 6157807202322611536 })
[2023-09-01T17:52:25Z WARN portfolio_simulation::strategies] Shrinking order output size by 0.01%
[2023-09-01T17:52:25Z WARN portfolio_simulation::strategies] Swap failed due to revert: Portfolio_InvalidInvariant(Portfolio_InvalidInvariant { prev: 6162663215956134642, next: 6161556751258908410 })
[2023-09-01T17:52:25Z WARN portfolio_simulation::strategies] Shrinking order output size by 0.01%
[2023-09-01T17:52:25Z WARN arbiter_core::manager] Stopped running environment labeled portfolio
Notice the large previous invariant value.
Background
All of this can be achieved running at commit a696d82eac41abff875c55bdd47135b09932e5ca
In the simulation, we can set the config.toml
as so:
[environment_parameters]
label = "portfolio"
block_rate = 10.0
seed = 0
[price_process_parameters]
# The following constants are used to configure the Ornstein-Uhlenbeck process
# The initial price of the asset.
initial_price = 1.0
# The mean (price) of the process.
mean = 1.0
# The standard deviation of the process.
std_dev = 0.001
# The theta parameter of the process.
# This describes how strongly the process will revert to the mean.
theta = 3.0
# The start time of the process.
t_0 = 0.0
# The end time of the process.
t_n = 1000
# t_n = 1
# The number of steps in the process.
num_steps = 25000
# Seed for the price processes
seed = 1
# We will need two tokens for the simulation.
# One will be the "asset", the other will be the "quote"
[asset_token_parameters]
name = "Arbiter Token X"
symbol = "ARBX"
decimals = 18
[quote_token_parameters]
name = "Arbiter Token Y"
symbol = "ARBY"
decimals = 18
# We need to set the parameters for the Portfolio pool
[portfolio_pool_parameters]
volatility_basis_points = 10
strike_price = 1.0
time_remaining_years = 1
is_perpetual = true
fee_basis_points = 5
priority_fee_basis_points = 0
# LP PARAMETRER
liquidity_mantissa = 1
liquidity_exponent = 20
initial_price = 1.0
# Simulation Parameters
[simulation_parameters]
number_of_paths = 1
Note that the liquidity given here represents 1E20
in wad units, so the maximum we expect either reserves (due to a strike price of 1) to be is X in [0,100] and Y in [0,100+k] where k is the invariant.
The seeding ensures perfect replayability. Taking this now, we can graph out some of these details:
If we zoom in to where we first see this happen, we can see some interesting phenomenon:
Notice that at 18533 to 18534 we see the invariant jump massively. Specifically, we have:
invariant_18533 == 214289665497284135 == 0.214289665497284135
invariant_18534 == 4633509197977427441 == 4.633509197977427441 wad
Also at this point, the arbitrageur massively overshoots the price correction and gains a profit in a single step that amounts to more than the profit up until that point. After this, the arbitrageur starts losing massively, presumably due to the disconnect between its understanding of the pool pricing and swap behavior and the behavior of the contract.
Let's move a bit further down and zoom in:
From the top down, we can see the portfolio price tracking the external exchange up to price change index 18565. At this point, the price remains constant and no more swaps occur until the 18574 mark.
Some things to note, from 18540 onward, we see behavior that is somewhat unexpected. The Y (quote) reserves remained tied to their boundary, while the X (asset) reserves are still undergoing change. Note that price of this strategy depends implicitly only on the (virtual) reserves of X, hence why price did continue to track.
From 18574 to 18575 we see that the Y reserves jump massively and jump beyond what we would expect the maximum reserves to be. Specifically:
y_reserves_18574 == 99990769527159934700 == 99.990769527159934700 wad
y_reserves_18575 == 484252902085083286100 == 484.252902085083286100 wad
Recall again that Y is bounded by [0,100+k] where k is the invariant (and given we have 100*1E18 liquidity), so the large jump in the invariant allows for this to occur.
Solved by the linked commit, however, introduces a new issue described in #442