Skip to main content

Withdrawals

Domination Finance liquidity is stored in DomFiVault. When the vault is healthy, withdrawals can be made with the standard ERC4626 withdraw and redeem methods. When the vault is unhealthy, LPs must first make a withdraw request.

Withdraw Fees

To encourage long-term, stable deposits, Domination Finance charges a fee for deposits and withdraws. This is currently 0.1% for deposits and 0.1% for withdraws. These fees are set by FeeCalculator and distributed by FeeDistributor.

Withdrawing from a Healthy Vault

ERC4626 redeem

To redeem a certain amount of $DOMD, call

function redeem(Shares shares, address receiver, address account)

This will burn the specified shares of $DOMD from account and send the resulting collateral tokens, minus any withdraw fee, to receiver. The specified account must have shares available to redeem, and msg.sender must be the account or a manager of it. For more information, see ERC4626.redeem.

ERC4626 withdraw

To withdraw a certain amount of collateral, call

function withdraw(uint256 assets, address receiver, address account)

This will send assets to receiver, after any withdraw fee, by burning $DOMD from account. The specified account must have enough $DOMD available to produce assets when burnt, and msg.sender must be the account or a manager of it. For more information, see ERC4626.withdraw.

Withdrawing from an Unhealthy Vault

When the utilization ratio is too high, liquidity is gradually released to LPs over time. This helps Domination Finance avoid bank runs.

utilization ratio

"utilization ratio" is defined as

totalOpenInterestvault balance+pending trader lossespending trader gainspending withdrawals\frac{totalOpenInterest}{vault\ balance + pending\ trader\ losses - pending\ trader\ gains - pending\ withdrawals}

where totalOpenInterest is outstanding commitments to traders. Other platforms reference "collateralization ratio", the inverse of this number.

Below the "healthy utilization ratio" of 80%, traders can withdraw instantly. Above 80%, each additional 10% utilization draws out LP withdrawals by 24 hours, up to a maximum of 10 days.

makeRedeemRequest

When the vault is unhealthy, withdraws must be initiated by calling

DomFiVault.makeRedeemRequest(address account, Shares shares, address receiver)

For convenience, if the vault is healthy, this will instantly redeem shares and return collateral to receiver. Otherwise, it will create a WithdrawRequest which gradually enables the standard ERC4626 withdraw and redeem methods.

Withdraw Requests

A WithdrawRequest looks like this:

struct WithdrawRequest {
uint256 assets;
Shares shares;
Shares sharesRedeemed;
uint64 penalty;
uint64 beginsAt;
uint64 duration;
}

Requests become available linearly as duration seconds elapse, and can be executed gradually or all at once. Once 100% of a request is available, users have a grace period of 1 day to complete the withdrawal before their request expires. For instance, given the request

struct WithdrawRequest {
assets = 345345;
shares = 100;
sharesRedeemed = 0;
beginsAt = 2023-01-01 00:00;
duration = 6 days;
penalty = 0 days;
}

The owner could

  • redeem all 100 shares at 2023-01-07 00:00
  • redeem all 100 shares at 2023-01-07 23:59
  • redeem 50 shares on 2023-01-04 and the remaining 50 shares at 2023-01-07 23:59
  • redeem 25 shares on 2023-01-02 12:00 and let the rest of the request expire, keeping 75 shares in the vault
  • redeem 1 share every 90 minutes until the request was completed
  • etc.

LP shares are fungible tokens, so requests cannot not travel "with" them. Instead, making a withdraw request locks that part of a user's token balance until the request is done.

Request Execution

Once a withdraw request is ready, it can be executed by calling the usual withdraw and redeem methods. A request will remain fully available for 24 hours, at which point it will expire.

A fully available request allows a user to redeem up to shares $DOMD for the lesser of

  • previewRedeem() at the time of request
  • previewRedeem() at the time of execution

If rates were locked when requests were created, individual depositors could protect themselves against loss at the cost of other depositors. They would place withdraw requests, and if the vault balance went down they would execute the requests at the old, high price and redeposit at the new, low price. If the vault balance went up they would let the request expire.

If withdraw requests did not lock in an execution price at all, LPs would still benefit from trader fees while they were in the process of pulling their liquidity. We want only dedicated liquidity providers to benefit from Domination Finance.

Request Duration

request length
request.duration=TOTAL_DELAY_PER_UTILIZATION_RATIO×(vault utilizationHEALTHY_UTILIZATION_RATIO)×requested vault fraction\begin{align*} request.duration =& \texttt{TOTAL\_DELAY\_PER\_UTILIZATION\_RATIO} \\ &\times (vault\ utilization - \texttt{HEALTHY\_UTILIZATION\_RATIO}) \\ &\times requested\ vault\ fraction \end{align*}

DomFiVault has a global constant TOTAL_DELAY_PER_UTILIZATION_RATIO. This is the number of seconds required to withdraw 100% of the vault balance per utilization over HEALTHY_UTILIZATION_RATIO (80%). It's set to 100 days, so

  • At 120% utilization (40% over the safe ratio), withdrawing 10% of the vault balance would take 100 days * 40% * 10% = 4 days.
  • At 90% utilization (10% over the safe ratio), withdrawing 5% of the vault balance would take 100 days * 10% * 5% = 12 hours.
  • etc.

Request lengths are capped at MAX_WITHDRAW_DELAY, currently 10 days, in the case of very high utilization or very large withdraw requests.

If utilization is ever negative (meaning that the vault is underwater on its obligations), withdrawals will have a length of MAX_WITHDRAW_DELAY.

Request Penalties

Consider a naive user Alice and crafty user Mallory. Both have deposited $100 into the vault, which is undercollateralized. Alice plays by the rules: if she decides to withdraw, she makes a withdraw request and executes it when it's ready. Mallory keeps a withdraw request open all the time, even when he's not planning to withdraw. He makes new requests as soon as the old ones expire.

What if there is a run on the bank? Alice requests a withdrawal and must wait a while to remove all her liquidity. But Mallory already has a request open. He can immediately withdraw some (on average, 50%) of his funds and has a shorter wait (on average, half as long as Alice). This is not fair to Alice. Furthermore, since the optimal strategy is to have a withdraw request ready, competitive depositors all have to waste time and gas doing this.

To prevent gaming the system, we institute a withdraw delay penalty. Each user has a nextPenaltyRate and a total remainingPenaltySeconds, both normally 0. If a request expires, we increase both quantities by the following:

penalty increment
penaltyRate=durationsharespenaltySeconds=penaltyRate(sharessharesRedeemed)PENALTY_DURATION_MULTIPLIER\begin{align*} penaltyRate =& \frac{duration}{shares}\\ penaltySeconds =& penaltyRate * (shares - sharesRedeemed) * \texttt{PENALTY\_DURATION\_MULTIPLIER}\\ \end{align*}

Future requests will incur a penalty of nextPenaltyRate * shares, up to a total of remainingPenaltySeconds, and when completed they decrease remainingPenaltySeconds by the elapsed penalty time. Once remainingPenaltySeconds reaches zero, the penalty is cleared and future requests instantly begin to disburse. Note that waiting without opening a request also counts as "time served", decreasing the penalty paid by future requests.

Let's return to Alice and Mallory. Say the utilization ratio is 100%, so withdrawal requests take 2 days to activate.

Mallory makes a WithdrawRequest for his $100 at t=0. At t=2 days, it expires. He now faces 2 days of penalty all together, applied to his next requests at a rate of 2 days penalty per $100 requested. After 2 days pass, he can make another request. If a bank run occurs at a random time, he will have an average of at least 2 days remaining before withdrawing all his funds, the same as Alice.

But even though they average the same total time to withdraw their funds during a bank run, Mallory still has an advantage. If a bank run occurs at a random point in the cycle, Mallory has a 50% chance of having some tokens immediately available. Alice is always starting from 0. To mitigate this, we have added a PENALTY_DURATION_MULTIPLIER, currently 1.25x. This makes Mallory's average time to withdraw worse than Alice's. If, despite the penalty system, users are still trying to "jump the line" with Mallory's strategy, we can increase PENALTY_DURATION_MULTIPLIER until the strategy no longer makes sense.

Request Transfer Lock

An active withdraw request for shares $DOMD tokens causes transfers to revert if they would lower the sender's balance below shares. Users should think of making a withdraw request as "locking" their $DOMD until the withdraw is ready.

An accumulated penalty also prevents $DOMD transfers. Otherwise, users could avoid penalties by transfering their tokens to another account. Users with accumulated penalties cannot transfer $DOMD until a withdraw request of the same size, created as soon as their last request expired, would have become available.