Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate developer portal docs #427

Merged
merged 14 commits into from
Nov 1, 2024
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Account Architecture

## Overview
![Account Architecture](../../static/img/02-Architecture%20Overview/architecture-overview.png)

## WhirlpoolsConfig
The owner of a Config account has the authority to define the many authorities over the pools that it owns (ex. default fees, collect protocol fees etc) . Whirlpools visible on the ORCA UI are all derived and controlled by a WhirlpoolsConfig account owned by the ORCA foundation. To learn more about managing pools, start [here](../03-Whirlpools%20SDK/02-Whirlpool%20Management/01-Create%20Pool.md).

Users and other protocols are free to deploy their own WhirlpoolsConfig account on our Whirlpool program to spawn their own set of liquidity pools.

## WhirlpoolConfigExtension

WhirlpoolsConfig account may have WhirlpoolsConfigExtension account. WhirlpoolsConfigExtension account holds some additional authorities to manage TokenExtensions, especially TokenBadge accounts.

## FeeTier
FeeTier is an account that defines the fee rate, defined per WhirlpoolsConfig and tick spacing.

## Whirlpool
![Whirlpool Overview](../../static/img/02-Architecture%20Overview/whirlpool-overview.png)
A Whirlpool is a concentrated liquidity pool between a token pair (A & B).

Each Whirlpool account hosts the necessary information to deal with the accounting of the pool. It also hosts the PDAs to the vaults. Only the Whirlpool program has authority to withdraw from the vault. No one, not even the program owner or WhirlpoolsConfig owner, has the authority to withdraw.

A Whirlpool account is hashed by the Config, Token pair mints and tick spacing, so there can be many pools for the same trading pair but with a different tick-spacing.

Users are able to perform position management and fee/reward collection operations against the Whirlpool.

## TickArray
To learn about TickArry, read [Understanding Tick Arrays](./03-Understanding%20Tick%20Arrays.md)

## Position
Positions represents a set of liquidity distributed on a price range within a single Whirlpool. To learn more, read [Tokenized Positions](./04-Tokenized%20Positions.md)

## PositionBundle
By creating a PositionBundle, up to 256 positions can be managed by a single NFT. Also, by closing a position, a new position can be created on the same PositionBundle account, so there is no rent overhead when rebalancing.

If you manage many positions and open and close them frequently, there is no reason not to use PositionBundle.

## TokenBadge
This account was introduced to support TokenExtensions.

While TokenExtensions provides useful extensions, there are extensions that pose a risk to the pool and pool users.

Therefore, tokens with some extensions can only be used for pool initialization if TokenBadge authority has issued a TokenBadge for that token.

## How are Whirlpool Accounts stored
Whirlpool program accounts are all [Program Derived Addresses](https://solana.com/docs/core/pda) (PDA) derivable from another Whirlpool account up the hierarchy.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Price & Ticks

## Tracking Price
Whirlpool tracks price using **square-root price**. Each pool supports a sqrt-price range between $\left[ 2^{-64}, 2^{64} \right]$.

## Tick
Users can deposit liquidity on a custom price range in a Whirlpool. The smallest unit of price measurement (**tick**) is 1bps. Whirlpool represents the price range as a sequence of ticks and stores accounting information in each initialized tick that hosts liquidity.

Sqrt-price maps to a tick with the formula below. Each tick represents 1 basis point of change from the neighboring tick.
$$
\sqrt{p}(i) = \sqrt{1.0001}^{i}\\
$$
Given the supported price-range of $\left[ 2^{-64}, 2^{64} \right]$, the tick range for a Whirlpool is $\left[ -443636, 443636 \right]$.

The Whirlpool account tracks both the current sqrt-price and the current tick-index.

## Understanding Tick Spacing
Due to compute cost and rent constraints, it is often not economical for a Whirlpool to allow users to deposit liquidity into every single tick. Whirlpools requires pool owners to define an additional "Tick-Spacing" parameter. This allows them to define the space between "initializable ticks", where liquidity information can be stored.

A tick-spacing of 5 means that liquidity can be deposited into tick-index that are a multiple of 5. (ex. [...-10, -5, 0, 5, 10...]).

As a general rule, the smaller the expected volatility of a pool is, the smaller tick-spacing should be. To help you decide on the best tick-spacing for your whirlpool, consider the following attributes.

### 1. Granularity of user definable price ranges
The smaller your tick-spacing, the more granular the price users can deposit their liquidity in. For more stable pools, a more granular tick-spacing would let users define a tighter range to maximize their leverage.

**Tick Spacing = 1**
| **Price** | **Initializable Tick Index** |
|---|---|
| 1.0001^{-2} = \frac{1}{1.00020001} | -2 |
| 1.0001^{-1} = \frac{1}{1.0001} | -1 |
| 1.0001^0 = 1 | 0 |
| 1.0001^1 = 1.0001 | 1 |
| 1.0001^2 = 1.00020001 | 2 |

**Tick Spacing = 100**
| Price | **Initializable Tick Index** |
|---|---|
| 1.0001^{-200} = \frac{1}{1.0202003198939318} | -200 |
| 1.0001^{-100} = \frac{1}{1.0100496620928754} | -100 |
| 1.0001^0 = 1 | 0 |
| 1.0001^{100} = 1.0100496620928754 | 100 |
| 1.0001^{200} = 1.0202003198939318 | 200 |

### 2. Maximum price movement per swap
The size of the tick-spacing defines the maximum price movement a single swap can move the price by for a Whirlpool.

Whirlpool's swap operates by iterating through each ticks with initialized liquidity. The larger the gap between initialized ticks are, the more it can theoretically traverse the price range.

A low tick-spacing pool undergoing a massive price movement may require multiple swap instructions to complete the price movement. Therefore, more volatile pairs that often has large price swings should look at higher tick-spacing to mitigate this pain point for their pool users.

### 3. Account rent cost for users
On-chain storage requires account space, and the more data a program needs to store, the higher the rent required. With larger tick-spacing, fewer ticks are needed to manage liquidity across a set price range, reducing the storage cost for users.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Understanding Tick Arrays
![TickArray Account Architecture](../../static/img/02-Architecture%20Overview/tickarray-overview.png)

A sequence of ticks are stored in individual **tick-array** accounts on chain. Each whirlpool has a sequence of tick-array accounts to host the entire tick range.

A tick-array is keyed by the start-index of its hosted ticks and can hold 88 physical ticks in an array. It only hosts the tick objects for the initializable tick indices based on the Whirlpool's tick-spacing. The total range for a tick-array is therefore 88 * tick-spacing.

**Tick Array Account Info**
- Number of physical tick slots - 88
- Account Size - 10kb

## Usage in Whirlpool Program Instructions
When you interact with ticks on Whirlpool instructions, often you will need to derive the correct tick-array so the program can get access to the designated tick object. This tick-array is a PDA derived using the Whirlpool pool’s public key and the start tick index of the tick array, which defines the beginning of a specific range of ticks.

For example, if the current tick is 200, the tick spacing is 2, and each tick-array contains 88 ticks, you can compute the start tick index by first finding the closest multiple of tick_spacing * ticks_per_array that is less than or equal to the current tick. Here, the start tick index would be 176, calculated as (200 // (2 * 88)) * (2 * 88).

### Open Position
When a position opens up in a new tick or price range, the tick-array must be initialized before the position can be created. This means the user invoking the position will need to cover the rent-exempt cost for the tick-array account, which is 10 KB in size.

Once a tick-array account is set up, it cannot be closed and will never need to be reinitialized. For this reason, Whirlpool owners may consider preemptively initializing tick-array ranges to prevent unexpected costs for users.

### Adjust Liquidity (increase / decrease liquidity)
Users of these instructions must provide the tick-arrays that contain the specified tick indexes. For each instruction, two tick-arrays need to be passed in—these may be the same array if the range is small. The instruction requires access to these accounts to read the appropriate Tick objects effectively.

### Swap
Swap users will have to provide the series of tick-arrays that the swap will traverse across.

The first tick-array in the sequence typically houses the Whirlpool's current tick index, though this is not always required. In some cases, such as with the new swap instruction, users can pass in up to six tick-arrays, with only three arrays being crossed during a swap. For example, the Whirlpools SDK preemptively provides the tick-array containing the current price, along with two arrays below and two above it, ensuring adequate coverage for different price ranges.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: How about moving In some cases, ... ensuring adequate coverage for different price ranges. to after The second and third tick ... tick-array public key..

In this sentence, I think we explain about "first tick-array". So current description flow looks the following to me.

  • first tick array
  • Sparse swap improvement
  • second and thirt tick array


The second and third tick arrays are the next tick-arrays in the swap direction. If the user knows the swap will not traverse to the next tick-array, or it's simply not possible at both ends of the price range, they can just put in any tick-array public key.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## Tokenized Positions
Whirlpool Position ownership is represented by a non-fungible token in the owner's wallet.

## Anatomy of a Position

There are 3 main accounts used to represent a Tokenized Position on Whirlpool.

1. **Postion Account** - The actual [account](https://github.com/orca-so/whirlpools/blob/2c9366a74edc9fefd10caa3de28ba8a06d03fc1e/programs/whirlpool/src/state/position.rs#L20) hosting the position's information. The PDA is derived from Whirlpool Program Id and Position Mint.
2. **Position Mint Account** - The spl-token mint of the NFT minted to represent this position.
3. **Position Associated Token Account** - The [ATA](https://spl.solana.com/associated-token-account) of the mint-token that will house the minted token in the user's wallet.

The program will verify that a user owns a position by checking whether the wallet provided has the correct position token in it.

### Creating a Position
Positions are created using the [open_position_with_token_extensions](https://github.com/orca-so/whirlpools/blob/main/programs/whirlpool/src/instructions/open_position_with_token_extensions.rs) instruction and it does the following:
1. The caller will provide a brand new token mint and the PDA of the [Position](https://github.com/orca-so/whirlpools/blob/2c9366a74edc9fefd10caa3de28ba8a06d03fc1e/programs/whirlpool/src/state/position.rs) account derived from the Whirlpool.
2. `open_position_with_token_extensions` will initialize the mint, mint 1 token to the `position_token_account` and immediately burn the mint authority of this mint.
3. The position account is initialized with the set tick range and is ready to receive new liquidity via the [increase_liquidity](https://github.com/orca-so/whirlpools/blob/2c9366a74edc9fefd10caa3de28ba8a06d03fc1e/programs/whirlpool/src/instructions/increase_liquidity.rs) instruction.

## Traits of a Whirlpool Position
- The tick range is fixed upon creation and cannot be adjusted afterward. To re-balance, users need to close their position and open a new one with the desired tick range.
- Position tokens can be freely transferred. Whoever holds the token in their wallet has the authority to manage the position account, allowing them to increase or decrease liquidity, harvest fees, and close the position.

## NFT Metadata
Whirlpools utilizes the Token2022 program for position NFTs, leveraging the MetadataPointer and TokenMetadata extensions to eliminate the need for Metaplex metadata accounts and associated costs. Advanced users can also choose to exclude metadata entirely.
Copy link
Collaborator

@yugure-orca yugure-orca Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think to eliminate ... associated costs part can be replaced with to make all rent refundable. 🙂
non-refundable rent is really pain for LPer 😢

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Understanding Whirlpool Fees

When a user performs a swap on a Whirlpool, a percentage of the swap input amount may be taken as a fee, allocated between liquidity providers and a protocol fee.

## Total Fee

On the protocol, the total fee collected from the user is referred as the fee-rate. It is stored as a hundredths of a basis point on the [Whirlpool](https://github.com/orca-so/whirlpools/blob/2c9366a74edc9fefd10caa3de28ba8a06d03fc1e/programs/whirlpool/src/state/whirlpool.rs) account.

A 0.01% (1bps) swap fee would equate to a fee_rate value of 100.

$$
\text{swap\_fee} = \frac{\text{input\_amount} \times \text{fee\_rate}}{1000000}
$$

## Fee Breakdown
### ProtocolFee
The `protocol_fee` is the fee diverted to a wallet that only the WhirlpoolConfig's `collectProtocolFeesAuthority` can collect. Often, this is used as the treasury of the protocol hosting the Whirlpools program.

It is stored as a basis point of the total fees collected on the Whirlpool account. For example, 3% of the total swap fee is diverted to the protocol would have a protocol_fee value of 300.

$$
\text{protocol\_fee} = \frac{\text{swap\_fee} \times \text{protocol\_fee\_rate}}{10000}
$$

### Liquidity Provider Fee
The liquidity providers get all of the remaining fees once the protocol fee is subtracted.

$$
\text{LP\_fee} = \text{swap\_fee} - \text{protocol\_fee}
$$
Loading
Loading