Managing a Vault

Basics

Anyone create their own vault and open it up for users to deposit. If you have some good option-related strategies, it's very likely that you can turn that into a vault, become the owner of the vault and allow more users invest in your strategy.

The most important feature about Opyn Perpetual Vault is to make "products with expiry" into "perpetual investment strategies." That's why there will be life "cycles" (or what we called rounds), because there needs to be an admin (or a decentralized network) to trigger the rollover of the strategy. If your strategy doesn't involve any use of oTokens (Opyn options), futures, bonds, or anything that has an expiry, then it's very likely that you're looking at the wrong document 🥺.

Lifecycle

The vault can have 3 states: Locked, Unlocked and Emergency. Under normal operation, only the locked and unlocked states matter.

Upon initialization, the vault starts out in the Unlocked state. In this state anyone can burn their shares and take out deposited assets, or deposit assets and get a vault share out of it. The vault owner can start a new round by calling rollover(). This puts the vault into a Locked state, during which the vault will no longer accept direct withdraws or direct deposits. The vault goes back into an Unlocked state once closePositions() is called.

There is a minimum Unlock Period for each vault, which gives users the right to withdraw their full shares before the next round starts. Different vaults may set different minimal period, but this cannot be changed after the vault is created. The vault goes into an Emergency state when emergencyPause() is called by the owner. During this state, all functionality on the vault is paused. No user can deposit or withdraw any funds. When the resumeFromPause function is called, the vault starts back at whatever the state was before the pause.

User Interactions

User Deposit

Unlocked State

When the vault is unlocked, the user can call deposit(_amount) to deposit the asset and receive shares. All assets deposited in the unlocked state is used in the strategy once a new round starts. Once a new round starts, the vault goes into a locked state and the total asset already in the vault is distributed in whatever specified proportions to different actions to take on risk to earn premiums.

Locked State

Once the vault is locked, the user will not be able to deposit asset that is immediately put to use. This is to prevent users from joining right before the expiry of an option and taking a share of the total profit from the last round without taking on any of the risk.

When the vault is locked, users need to call registerDeposit which will transfer their assets to the pending queue in the vault. Assets in the pending queue will be used in the next round to earn premium, but until the current round ends will not earn any premium. The assets deposited during the locked state are just sitting idle in the vault. When closePositions() is called, the current round ends. All the assets from the pending queue is now part of the main pool and shares for all the depositors is minted and sent to the main vault. To actually transfer the shares to the respective depositors, anyone can call claimShares.

Withdraw

When the vault is Unlocked, a user can call withdraw which will burn his shares and send him back his collateral.

When the user is Locked, a user can still register a withdraw with registerWithdraw. The exact payout will be determined after the current round is over. After the round is over, the user can claim his deposit back anytime with withdrawFromQueue.

Owner Interactions

Rollover

The owner of the vault has to call rolloverPositions to start the next round. This will distribute assets in the vault into action contracts, meanwhile triggering the rolloverPosition function defined by each action.

Each action can implement custom logic in rolloverPosition to revert in some conditions to protect the user or stop a malicious rollover. For example, an option selling action may implement a time lock to enforce the owner to commit to an otoken to sell for locking period, before the sell is executed. This is to prevent a malicious seller from selling a $0 strike price call at a low price to effectively take out all the money from the action.

Close Positions

After the round is over (option expires .. etc), anyone can call closePositions to pull the money back to the vault to allow withdraw (set the vault back to unlocked state), and wait for the next round to begin.

When close position is called, the vault will try to pull back the asset from each action contract. Therefore each action contract should have approved that transfer, and make sure to have the amount of token reported by currentValue() to be pulled back from the vault.

Each action can also implement custom logic to prevent a malicious closePosition call. For example: a short action (selling option) should revert if the closePosition is called before oToken expires.

Owner Rollover Example

Here, we continued with the vault and short action we deployed in QuickStart. We will run through some example & stimulation that should help u understand the overall workflow of managing a vault.

How to make a profit

As a vault owner of a short call vault, you need to first commit to an otoken that you're gonna sell in the next round on the action we deployed (MyAction). You can go to GammaPortal oToken List to pick a call option that you wanna try selling in our action. It might be easier if you just create a custom call in the oToken Factory.

In this example, I created a call that's gonna expire tomorrow, so I can test the settlement tomorrow 😎.

After creating the otoken, you can copy the new otoken's address by clicking on the copy icon on the output.

Commit a Trade

In order to protect vault share holders, there is commit mechanism in the example actions. You should set a MIN_COMMIT_PERIODsuch that users have time to verify the new otoken you're committing to trade is aligned with the strategy.

To commit to an oToken, go to the MyAction contract you just created and verified on Etherscan, find the commitOToken function, and send the transaction with the new otoken address u created.

Stimulate a deposit

Let's stimulate the scenario where someone deposit in your vault. To do this, easily go to the ETHProxy contract and connect any account that has eth in it, and use depositETH function to deposit and get some vault shares.

Rollover and start a new round

Now we have committed to the next otoken to sell, we can try rolling the vault into the first round and start trading. To do this, go to the vault contract on Etherscan and run rollOverwith parameter [10000] , which means we're sending all 100% of the fund to our own action (MyAction)

Stimulate a trade from action

We will use the second address derived from your mnemonic to be the buyer. Make sure this address have at least 0.05 WETH ready. If you don't have it, get some eth from faucet first, and go to the weth contract on kovan to wrap some ETH into WETH.

Now let's execute an OTC order and make a profit!

In this example we control both the signing key that buys the options and are the owner of the vault, but in many cases these would be different entities.

To create and execute an OTC order for this example, open the sample script scripts/create-airswap-order-and-trade.ts and update the following 2 lines. This script serves an example for this exercise, but would need to be modified for more general use. Constants on order size, collateral and option price are also hard coded for this example, but would need to be adjusted for a more general use case.

async function main() {
// edit these
const otokenToBuy = '' // the otoken the vault committed to sell
const actionAddress = '' // the action address
}

And the run the script by:

npx hardhat run scripts/create-airswap-order-and-trade.ts --network kovan

This script will automatically create an order, sign it with signer's key, and let the owner call mintAndTradeAirSwapOTC to execute the trade on behalf of the vault.

Closing position:

Now your vault already make some profit, if the option doesn't expire in the money tomorrow, we will successfully make our share holders some money 😋

Once the option expires, go to the vault on Etherscan and call closePositions.