Perpetual Swap Contract Specs & Simulations

• Updated

Overview

This document provides detailed specs and math behind critical protocol functions.

Account Specs

\begin{aligned} collateralRatio &:= \text{the proportionate of USD value of a collateral that can be used in perpetual swap} \\\\ settlementCollateral &:= \text{balance of USDC in vault} \\\\ nonSettlementCollateral &:= \sum_{c=nonSettlement Collateral}{Balance_{c} \ \times indexTwap_{c} \times collateralRatio_{c}} \\\\ collateral &:= settlementCollateral + nonSettlementCollateral \\\\ owedRealizedPnl &:= \text{realized PnL (in USD) that hasn't been settled(include funding payment and collected maker fees)} \\\\ \text{settling } collateral &:= \begin{cases} settlementCollateral &\leftarrow settlementCollateral + owedRealizedPnl \\ owedRealizedPnl &\leftarrow 0 \end{cases} \\\\ pendingFundingPayment &:= \text{funding payment (in USD) that hasn't been settled} \\\\ \text{settling } funding &:= \begin{cases} owedRealizedPnl &\leftarrow owedRealizedPnl + pendingFundingPayment \\ pendingFundingPayment &\leftarrow 0 \end{cases} \\\\ settlementCollateralBalance &:= settlementCollateral + owedRealizedPnl + pendingFundingPayment + pendingFee \\\\ settlementCollateralValue &:= settlementCollateralBalance + unrealizedPnl \\\\ accountValue &= \underbrace{collateral + owedRealizedPnl + pendingFundingPayment + pendingFee}_{totalCollateralValue} + \underbrace{\sum_{market}{unrealizedPnl_{market}}}_{totalUnrealizedPnl} \\ &= collateral + owedRealizedPnl + pendingFundingPayment + pendingFee + \underbrace{\sum_{market}{positionValue_{market}}}_{totalPositionValue} + netQuoteBalance \\\\ netQuoteBalance &:= \text{quote position/exposure of this account(does not include pending fee or collected fees)} \\ &= vQuote_{balance} + vQuote_{inPool} \\ vQuote_{balance} &:= \text{unused (positive) or owed(negative) quote token of this account in a specific market} \\ &= \sum_{market}{vQuote_{balance,market}} \\ vQuote_{inPool} &= \sum_{market}{vQuote_{liquidity,market} + vQuote_{owedFee,market}} \\ vQuote_{liquidity,market} &:= \text{amount of quote tokens the trader added to the market pool} \\ vQuote_{owedFee,market} &:= \text{amount of the trader's unclaimed quote tokens as pool fees} \\\\ openOrderMarginReq(ratio) &:= \text{open order margin requirement (total collateral locked due to open orders)} \\ &= (\sum_{market}{vBaseValue_{debt,market}} + vQuoteValue_{debt}) \times ratio \\\\ vBaseValue_{debt,market} &= vBase_{debt,market} \times vBaseIndexPrice_{market} \\ vQuoteValue_{debt} &= vQuote_{debt} \times 1 \\ vQuote_{debt} &= abs(min(0, \sum_{market}{vQuote_{balance,market}}))\\\\ imRatio &:= \text{initial margin requirement ratio} \\\\ mmRatio &:= \text{maintenance margin requirement ratio(for position liquidation)} \\\\ freeCollateral_{withdrawal} &:= \text{the maximum USD value for withdrawal or opening new positions/orders} \\ &= freeCollateral(imRatio) \\\\ freeCollateral_{cancelOrder} &:= \text{negative means excess orders and can be cancelled} \\ &= freeCollateral(mmRatio) \\\\ freeCollateral(ratio) &= \begin{cases} min(totalCollateralValue, accountValue) - openOrderMarginReq(ratio), &\text{conservative, currently in use}\\ min(totalCollateralValue, accountValue - openOrderMarginReq(ratio)), &\text{moderate, Perp v1}\\ accountValue - openOrderMarginReq(ratio), &\text{aggresive, FTX} \end{cases} \\\\ freeCollateralByToken &:= \begin{cases} min(freeCollateral, max(0, settlementCollateralBalance)) ,&\text{for settlement collateral} \\ min(\frac{freeCollateral_{withdrawal}}{indexTwap \times collateralRatio}, balance_{nonSettlementCollateral}),&\text{for non-settlement collateral( settlementCollateralBalance >= 0)}\\ 0,&\text{for non-settlement collateral( settlementCollateralBalance < 0)} \end{cases} \\\\ buyingPower_{market,increasePosition} &= \frac{freeCollateral_{withdrawal}}{imRatio} \\ buyingPower_{market,reversePosition} &= |positionValue_{market}| + buyingPower_{market,closed} \\ buyingPower_{market,closed} &:= \text{estimated buying power after the current position is closed} \end{aligned}

Liquidation

\begin{aligned} accountMarginRatio &= \frac{accountValue}{\sum_{market}{|positionValue_{market}|}}\\\\ mmRatio &:= \text{maintenance margin ratio (account will be liquidated if its margin ratio falls below)} \\ accountMarginRatio &< accountMaintenanceMarginRatio \implies \text{liquidation (any market)!} \\\\ accountMaintenanceMarginRatio &= \frac{\sum_{market}{mmRatio_{market} \times |positionValue_{market}|}}{\sum_{market}{|positionValue_{market}|}} \\ &= \frac{mmRatio \times \sum_{market}{|positionValue_{market}|}}{\sum_{market}{|positionValue_{market}|}}, \text{ since currently all markets share the same mmRatio} \\ &= mmRatio \\\\ liquidationPenaltyRatio &:= \text{percentage paid by the trader to the liquidator when being liquidated} \\ liquidationFee &:= \text{actual amount paid by the trader to the liquidator} \\ &= exchangePositionNotional \times liquidationPenaltyRatio \end{aligned}

Open Orders & Cancel Excess Orders

\begin{aligned} (freeCollateral_{cancelOrder} < 0) \lor (accountMarginRatio < accountMaintenanceMarginRatio) \\ \implies \text{burn liquidity (cancel excess open orders)!} \end{aligned}

Market Specs

Margin

\begin{aligned} unrealizedPnl &= positionValue + openNotional \\\\ positionValue &= positionSize \times vBaseIndexPrice \\\\ openNotional &:= \text{cost basis (in USD) of an open position} \\ &\text{i.e. amount of quote the trader owed(-) or gained(+) as a result of the open positions} \\ &= vQuote_{balance} + vQuote_{liquidity}\\\\ positionSize &:=\begin{cases} > 0, &\text{if long}\\ < 0, &\text{if short} \end{cases} \\ &= vBase_{balance} + vBase_{liquidity} \\\\ vBase_{balance} &:= \text{amount of unused(positive) or owed(negative) base tokens of the account in this market} \\ &\text{It may only change due to trading} \\ vBaseIndexPrice &:= \text{external market price of the underlying asset} \\ vBaseValue_{debt} &= vBase_{debt} \times vBaseIndexPrice \\ vBase_{debt} &= abs(min(0, vBase_{balance})) \\\\ vQuote_{balance} &:= \text{amount of unused(positive) or owed(negative) quote tokens of the account in this market} \\ &\text{It may change due to (1) adding/removing liquidity, (2) trading, and (3) realized PnL.} \\\\ vQuote_{liquidity} &:= \text{amount of quote tokens the trader(maker) added as liquidity to the pool} \\ \\\\ maxLeverage &= \frac{1}{imRatio} \end{aligned}

Taker/Maker Position

\begin{aligned} positionSize &= vBase_{balance} + \sum_{order}{vBase_{order,now}} \\ &= vBase_{balance,taker} + \sum_{order}{vBase_{open,order}} + \sum_{order}{vBase_{order,now}} \\ &= vBase_{balance,taker} + \sum_{order}{(vBase_{open,order} + vBase_{order,now})} \\ &= positionSize_{taker} + \sum_{order}{positionSize_{order}} \\\\ openNotional &= vQuote_{balance} + \sum_{order}{vQuote_{order,now}}\\ &= vQuote_{balance,taker} + \sum_{order}{vQuote_{open,order}} + \sum_{order}{vQuote_{order,now}} \\ &= vQuote_{balance,taker} + \sum_{order}{(vQuote_{open,order} + vQuote_{order,now})} \\ &= openNotional_{taker} + \sum_{order}{openNotional_{order}} \end{aligned}

When adding liquidity without using taker position, no changes to both taker & maker position:

\begin{aligned} \Delta vBase &:= \text{base token amount added} \\ \Delta vQuote &:= \text{quote token amount added} \\\\ positionSize_{taker,new} &= positionSize_{taker} \\\\ positionSize_{order,new} &= vBase_{order,open,new} + vBase_{order,now,new} \\ &= vBase_{order,open} - \Delta vBase + vBase_{order,now} + \Delta vBase \\ &= vBase_{order,open} + vBase_{order,now} \\ &= positionSize_{order} \\\\ positionSize_{new} &= positionSize_{taker,new} + \sum_{order}{positionSize_{order,new}} \\ &= positionSize_{taker} + \sum_{order}{positionSize_{order}} \\ &= positionSize \\\\ openNotional_{taker,new} &= openNotional_{taker} \\\\ openNotional_{order,new} &= vQuote_{order,open,new} + vQuote_{order,now,new} \\ &= vQuote_{order,open} - \Delta vQuote + vQuote_{order,now} + \Delta vQuote \\ &= vQuote_{order,open} + vQuote_{order,now} \\ &= openNotional_{order} \\\\ openNotional_{new} &= openNotional_{taker,new} + \sum_{order}{openNotional_{order,new}} \\ &= openNotional_{taker} + \sum_{order}{openNotional_{order}} \\ &= openNotional \end{aligned}

When adding liquidity with taker position, both taker & maker position should change accordingly, but total position should not change:

\begin{aligned} \Delta vBase &:= \text{base token amount added} \\ \Delta vQuote &:= \text{quote token amount added} \\\\ positionSize_{taker,new} &= vBase_{taker,new} \\ &= vBase_{taker} - \Delta vBase \\ &= positionSize_{taker} - \Delta vBase \\\\ positionSize_{order,new} &= vBase_{order,open,new} + vBase_{order,now,new} \\ &= vBase_{order,open} + vBase_{order,now} + \Delta vBase \\ &= vBase_{order,open} + vBase_{order,now} + \Delta vBase \\ &= positionSize_{order} + \Delta vBase \\\\ positionSize_{new} &= positionSize_{taker,new} + \sum_{order}{positionSize_{order,new}} \\ &= positionSize_{taker} - \Delta vBase + \sum_{order}{positionSize_{order}} + \Delta vBase \\ &= positionSize \\\\ openNotional_{taker,new} &= vQuote_{taker,new} \\ &= vQuote_{taker} - \Delta vQuote \\ &= openNotional_{taker} - \Delta vQuote \\\\ openNotional_{order,new} &= vQuote_{order,open,new} + vQuote_{order,now,new} \\ &= vQuote_{order,open} + vQuote_{order,now} + \Delta vQuote \\ &= openNotional_{order} + \Delta vQuote \\\\ openNotional_{new} &= openNotional_{taker,new} + \sum_{order}{openNotional_{order,new}} \\ &= openNotional_{taker} - \Delta vQuote + \sum_{order}{openNotional_{order}} + \Delta vQuote \\ &= openNotional \end{aligned}

When removing liquidity, both taker & maker position size and open notional should change accordingly, but total position should not change.

In addition, removing liquidity could trigger realized PnL if the taker position ends up reduced:

\begin{aligned} \Delta vBase &:= \text{base token amount removed} \\ & < 0 \\ \Delta vQuote &:= \text{quote token amount removed} \\ & < 0 \\\\ removeRatio &= \bigg|{\frac{\Delta liquidity}{liquidity}}\bigg| \\ &= \bigg|{\frac{\Delta vBase}{vBase_{order,now}}}\bigg| \\ &= \bigg|{\frac{\Delta vQuote}{vQuote_{order,now}}}\bigg| \\\\ \Delta vBase_{order,open} &= -(vBase_{order,open} \times removeRatio) \\\\ positionSize_{taker,new} &= vBase_{taker,new} \\ &= vBase_{taker} - \Delta vBase_{order,open} - \Delta vBase \\ &= positionSize_{taker} - \Delta vBase_{order,open} - \Delta vBase \\\\ positionSize_{order,new} &= vBase_{order,open,new} + vBase_{order,now,new} \\ &= vBase_{order,open} + \Delta vBase_{order,open} + vBase_{order,now} + \Delta vBase \\ &= positionSize_{order} + \Delta vBase_{order,open} + \Delta vBase \\\\ positionSize_{new} &= positionSize_{taker,new} + \sum_{order}{positionSize_{order,new}} \\ &= positionSize_{taker} - \Delta vBase_{order,open} - \Delta vBase + \sum_{order}{positionSize_{order}} + \Delta vBase_{order,open} + \Delta vBase \\ &= positionSize_{taker} + \sum_{order}{positionSize_{order}} \\ &= positionSize \\\\ \Delta vQuote_{order,open} &= -(vQuote_{order,open} \times removeRatio) \\\\ openNotional_{taker,new} &= vQuote_{taker,new} \\ &= vQuote_{taker} - \Delta vQuote_{order,open} - \Delta vQuote \\ &= openNotional_{taker} - \Delta vQuote_{order,open} - \Delta vQuote \\\\ openNotional_{order,new} &= vQuote_{order,open,new} + vQuote_{order,now,new} \\ &= vQuote_{order,open} + \Delta vQuote_{order,open} + vQuote_{order,now} + \Delta vQuote \\ &= openNotional_{order} + \Delta vQuote_{order,open} + \Delta vQuote \\\\ openNotional_{new} &= openNotional_{taker,new} + \sum_{order}{openNotional_{order,new}} \\ &= openNotional_{taker} - \Delta vQuote_{order,open} - \Delta vQuote + \sum_{order}{openNotional_{order}} + \Delta vQuote_{order,open} + \Delta vQuote \\ &= openNotional_{taker} + \sum_{order}{openNotional_{order}} \\ &= openNotional \end{aligned}

When swapping, taker position will change; if the maker liquidity is hit, then its position will change as well. Total position will also change accordingly:

\begin{aligned} \Delta vBase &:= \text{base token amount swapped} \\ \Delta vQuote &:= \text{quote token amount swapped} \\\\ positionSize_{taker,new} &= vBase_{taker,new} \\ &= vBase_{taker} + \Delta vBase \\ &= positionSize_{taker} + \Delta vBase \\\\ positionSize_{order,new} &= vBase_{order,open,new} + vBase_{order,now,new} \\ &= vBase_{order,open} + vBase_{order,now} + \Delta vBase_{order} \\ &= positionSize_{order} + \Delta vBase_{order} \\\\ positionSize_{new} &= positionSize_{taker,new} + \sum_{order}{positionSize_{order,new}} \\ &= positionSize_{taker} + \Delta vBase + \sum_{order}{positionSize_{order} + \Delta vBase_{order}} \\ &= positionSize + \Delta vBase +\sum_{order}{\Delta vBase_{order}} \\ openNotional_{taker,new} &= vQuote_{taker,new} \\ &= vQuote_{taker} + \Delta vQuote \\ &= openNotional_{taker} + \Delta vQuote \\\\ openNotional_{order,new} &= vQuote_{order,open,new} + vQuote_{order,now,new} \\ &= vQuote_{order,open} + vQuote_{order,now} + \Delta vQuote_{order} \\ &= openNotional_{order} + \Delta vQuote_{order} \\\\ openNotional_{new} &= openNotional_{taker,new} + \sum_{order}{openNotional_{order,new}} \\ &= openNotional_{taker} + \Delta vQuote + \sum_{order}{openNotional_{order} + \Delta vQuote_{order}} \\ &= openNotional + \Delta vQuote + \sum_{order}{(\Delta vQuote_{order} + \Delta fee_{order})} \end{aligned}

Realized PnL

Reducing taker position will realize PnL based on the reduction/close ratio. Note it applies to not only swapping but also removing liquidity, because removing liquidity could change taker position. Realized PnL will add to owedRealizedPnl as well as deduct from quote balance (both total & taker) to avoid double-counting:

\begin{aligned} realizedPnl_{exchange} &= \begin{cases} \Delta vQuote + openNotional_{taker} \times closeRatio, &closeRatio \leq 1 \\ \frac{\Delta vQuote}{closeRatio} + openNotional_{taker}, &closeRatio > 1 \\ \end{cases} \\\\ closeRatio &= \frac{|\Delta vBase|}{|positionSize_{taker}|} \\\\ vQuote_{\{balance|taker\}, new} &= \begin{cases} vQuote_{\{balance|taker\}} - \Delta vQuote_{liquidity}, &\text{add(+) liquidity} \\ vQuote_{\{balance|taker\}} - \Delta vQuote_{liquidity} - realizedPnl, &\text{remove(-) liquidity} \\ vQuote_{\{balance|taker\}} - realizedPnl, &\text{swap} \end{cases} \\\\ \end{aligned}

Exchange Fee

\begin{aligned} exchangeFeeRatio &:= \text{fee ratio charged for the swap} \\ fee_{exchange} &= \begin{cases} \Delta vQuote_{balance} \times feeRatio, &\text{if long}\\ exchangedPositionNotional \times feeRatio, &\text{if short} \end{cases} \\\\ insuranceFundFeeRatio &:= \text{percentage of fee charged by the insurance fund} \\ fee_{insuranceFund} &= fee_{exchange} \times insuranceFundFeeRatio \\\\ fee_{maker} &= fee_{exchange} - fee_{insuranceFund} \end{aligned}

Funding

Define funding payment as:

\begin{aligned} t &:= \text{a serial number representing the discrete time segment where the mark price remains in the same tick} \\ d(t) &:= \text{duration of time segment }t \\\\ iTwap(t) &:= \text{index TWAP at the end of time segment }t \\ mTwap(t) &:= \text{mark TWAP at the end of time segment }t \\ mp(t) &:= \text{mark price at the end of time segment }t \\\\ prem(t) &:= \text{premium at time segment }t \\ &= mTwap(t) - iTwap(t) \\\\ twPrem(t) &:= \text{time-weighted premium at time segment }t \\ &= prem(t) \times d(t)\\\\ funding(t) &:= \text{funding at time segment }t \\ &= \frac{posSize(t) \times twPrem(t)}{86400} \end{aligned}

\begin{aligned} posSize(t) &:= \text{position size at time }t \\ &= vBase_{balance}(t) + vBase_{liq}(t) \\\\ vBase_{balance}(t) &:= \text{a trader's base token balance (not in pool) at time }t \\ vBase_{liq}(t) &:= \text{a trader's base token balance in pool at time }t \end{aligned}

Given segment T between a trader's consecutive operations, we can assume that vBasebalance will not change within this segment.

Therefore:

\begin{aligned} \text{funding for segment }T &= \sum_{t}^{T}{funding(t)} \\ &= \sum_{t}^{T}{(vBase_{balance}(t) + vBase_{liq}(t)) \times twPrem(t)} \times \frac{1}{86400} \\ &= (\underbrace{vBase_{balance} \times \sum_{t}^{T}{twPrem(t)}}_{\text{balance coefficient}} + \underbrace{\sum_{t}^{T}{vBase_{liq}(t) \times twPrem(t)}}_{\text{liquidity coefficient}}) \times \frac{1}{86400} \end{aligned}

T can be separated into three states Ti, Tb, Ta ("range" is defined in Uniswap v3 [uni21]):

\begin{aligned} T_i &:= T_i \in T, \text{ segments where } mp(t) \text{ is in the range} \\ T_b &:= T_b \in T, \text{ segments where } mp(t) \text{ is below the range} \\ T_a &:= T_a \in T, \text{ segments where } mp(t) \text{ is above the range} \\ T &= T_i + T_b + T_a \end{aligned}

Since vBaseliq(t) can be derived as follows [uni21]:

\begin{aligned} vBase_{liq}(t) &= \begin{cases} 0 &, \text{ if } mp(t) \geq mp_u \\ \frac{l}{\sqrt{mp(t)}} - \frac{l}{\sqrt{mp_u}} &, \text{ if } mp_l \leq mp(t) < mp_u \\ \frac{l}{\sqrt{mp_l}} - \frac{l}{\sqrt{mp_u}} &, \text{ if } mp(t) < mp_l \end{cases} \end{aligned}

We have:

\begin{aligned} pf_r &:= \text{accumulated time-weighted premium inside the range} \\ pf_b(i) &:= \text{accumulated time-weighted premium below the tick }i \\ spf_{r} &:= \text{accumulated products of reciprocal-sqrt-mark-price and time-weighted premium inside the range per unit of virtual liquidity} \\\\ \sum_{t}^{T_i}{vBase_{liq}(t) \times twPrem(t)} &= \sum_{t}^{T_i}{(\frac{l}{\sqrt{mp(t)}} - \frac{l}{\sqrt{mp_u}}) \times twPrem(t)} \\ &= \sum_{t}^{T_i}{(\frac{l}{\sqrt{mp(t)}} \times twPrem(t))} - \frac{l}{\sqrt{mp_u}} \times \sum_{t}^{T_i}{twPrem(t)} \\ &= l \times (spf_{r} - spf_{r,last}) - \frac{l}{\sqrt{mp_u}} \times (pf_r - pf_{r,last}) \\\\ \sum_{t}^{T_a}{vBase_{liq}(t) \times twPrem(t)} &= \sum_{t}^{T_a}{0 \times twPrem(t)}, \text{ since } vBase_{liq}(t) \text{ is always 0 above the range} \\ &= 0 \\\\ \sum_{t}^{T_b}{vBase_{liq}(t) \times twPrem(t)} &= (\frac{l}{\sqrt{mp_l}} - \frac{l}{\sqrt{mp_u}}) \times (pf_b(i_l) - pf_{b,last}(i_l)) \end{aligned}

Where last means the value of the growth variable during the trader's previous operation, and l means the trader's virtual liquidity.

As a result:

\begin{aligned} \text{funding for segment }T &= (vBase_{balance} \times \sum_{t}^{T}{twPrem(t)} + \sum_{t}^{T}{vBase_{liq}(t) \times twPrem(t)}) \times \frac{1}{86400} \\ &= (\underbrace{vBase_{balance} \times (pf_r - pf_{r,last})}_{\text{balance coefficient}} + \underbrace{l \times (spf_{r} - spf_{r,last}) - \frac{l}{\sqrt{mp_u}} \times (pf_r - pf_{r,last})}_{\text{in-range-liquidity coefficient}} + \underbrace{(\frac{l}{\sqrt{mp_l}} - \frac{l}{\sqrt{mp_u}}) \times (pf_b(i_l) - pf_{b,last}(i_l))}_{\text{below-range-liquidity coefficient}}) \times \frac{1}{86400} \end{aligned}

Accounting

Based on the definition of exchange fee, funding payment and liquidation fee, we already know that:

\begin{aligned} \sum_{account}{realizedPnl_{exchange}} + \sum_{account}{fee_{maker}} + accountValue_{insuranceFund} &= 0 \\ \sum_{account}{funding} &= 0 \end{aligned}

Now assuming all trader (excl. insurance fund and liquidators) account positions are closed and all debts are repaid, we have:

\begin{aligned} accountValue &= totalCollateralValue \\ &= \sum{collateral_{deposited}} - \sum{collateral_{withdrawn}} + \sum{realizedPnl_{exchange}} + \sum{fee_{maker}} - \sum{funding} - \sum{liquidationFee} \end{aligned}

The liquidation fees are distributed among all liquidators accounts:

\begin{aligned} \sum{liquidatorAccountValue} = \sum_{liquidator}{accountValue} + \sum{liquidationFee} \end{aligned}

Combining all account values we have:

\begin{aligned} \sum_{account}{accountValue} &= \sum_{trader}{accountValue} + \sum{liquidatorAccountValue} + accountValue_{insuranceFund} \\ &= (\sum_{account}{collateral_{deposited}} - \sum_{account}{collateral_{withdrawn}} + \sum_{account}{realizedPnl_{exchange}} + \sum_{account}{fee_{maker}} - \sum_{account}{funding} - \sum_{account}{liquidationFee}) + \sum_{account}{liquidationFee} + accountValue_{insuranceFund} \\ &= \sum_{account}{collateral_{deposited}} - \sum_{account}{collateral_{withdrawn}} + \sum_{account}{realizedPnl_{exchange}} + \sum_{account}{fee_{maker}} - \sum_{account}{funding} + accountValue_{insuranceFund} \\ &= \sum_{account}{collateral_{deposited}} - \sum_{account}{collateral_{withdrawn}} \end{aligned}

Which means:

\begin{aligned} \sum_{account}{accountValue} + \sum_{account}{collateral_{withdrawn}} + \sum_{account}{collateral_{deposited}} + InsuranceFundBalance = 0 \end{aligned}

Simulations

Margin Model Comparison

As mentioned above, there are three different margin models for calculating free collateral. We use the following simulation to understand the properties of each model.

Margin Simulation

Detailed simulation on margin-related internal states. We use the following simulation to understand the expected contract behaviors under different scenarios.