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" is defined as
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 requestpreviewRedeem()
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
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:
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.