# **Whirlpool Program** In this document, you will learn all the necesary data to perfom a swap in the Whirlpool program. Useful links: - Whirlpool Documentation: https://orca-so.gitbook.io/orca-developer-portal/orca/welcome - Whirlpool Github repo: https://github.com/orca-so/whirlpools I assume you have already read the documentation and have some knowledge about what is a whirlpool and how to operate with the program. In order to perfom sucessfully a Swap you will need to call these instructions that establishes the global enviroment of the program: - initConfigAndFeeTier: Initializes a WhirlpoolsConfig account that hosts info & authorities and a fee_tier account usable by Whirlpools in a WhirlpoolConfig space. - initWhirlpool: Initializes a Whirlpool account. - initTickArrays: Initializes 3 tick_array accounts to represent a tick-range in the Whirlpool previously created. - OpenPosition: Open a position in a Whirlpool. The position will start off with 0 liquidity. - IncreaseLiquidity: Add liquidity to a position in the Whirlpool. - Swap: performs a swap. ## Before starting To utilize all these Whirlpool instructions, you will need to have completed the following steps: - Create Mint token A & B: the order is irrelevant since we will use a function that orders the mints for the future instructions. - Create token A & B ATAs for admin and user. - Mint tokens to admin and user ATAs. The most important thing is to ensure that the user has a balance in the Token A ATA; Token B doesn't need to have a balance. > The following steps involves 2 dependencies from Typescript: @orca-so/whirlpools-sdk and @orca-so/common-sdk. > > In the whirlpools-sdk dependency there are some useful functions that will help us to calculate some parameters required from some instructions To initialize the enviroment you can take as reference the parameters of this Whirlpool created on Mainnet: https://explorer.solana.com/address/DZiV1HEnLE8hU16Xs1cjThAY2twAke4QSpJpHgNwpd3h/anchor-account?customUrl=http%3A%2F%2Flocalhost%3A8899 ## initConfigAndFeeTier ``` async initConfigAndFeeTier(fields: InitConfigAndFeeTierFields) InitConfigAndFeeTierFields = { - WhirlpoolsConfig: anchor.web3.Keypair; - feeAuthority: anchor.Address; - collectProtocolFeesAuthority: anchor.Address; - rewardEmissionsSuperAuthority: anchor.Address; - defaultProtocolFeeRate: number; - tickSpacing: number; - defaultFeeRate: number; }; ``` - WhirlpoolsConfig: Keypair of the WhirlpoolsConfig to be initialized - feeAuthority: Authority authorized to initialize fee-tiers and set customs fees. - collectProtocolFeesAuthority: Authority authorized to collect protocol fees. - rewardEmissionsSuperAuthority: Authority authorized to set reward authorities in pools - defaultProtocolFeeRate: Establish a default value for the `protocol_fee_rate`. It is a portion of the total fee that is redirected to a specific wallet and can only be collected by the `collect_protocol_fees_authority`. - TickSpancing: This parameter defines the space between "initializable ticks", where liquidity information can be stored (Explained in Whirlpool documentation). This value can be for example 64. The `feeAuthority, collectProtocolFeesAuthority and rewardEmissionsSuperAuthority` parameters are not necesary to perform the swap, they are useful for some other instructions in the whirlpool program but we won't use it here, so the authority can be the admin pubkey. ## getAtoB function Once you create a Whirlpool, the Whirlpool program orders the token mint A & B in arbitrarily. So, even if you assign USDC to token A and Ki to token B, the program might set Ki token as Token A and USDC token as token B. This is due to their addresses and how the AMM operates with liquidity and swaps (for more information about this, refer to their documentation). To address this issue, all the instruction created in the sdk use the `orderMints` method from `PoolUtil` class in the `@orca-so/whirlpools-sdk`. Given two mint addresses, the method returns the same addresses but ordered. To understand the swap direction and how the tokens are ordered in the Whirlpool program, I created the `GetAtoB` instruction: ``` getAtoB = ( tokenMintAAddress: anchor.Address, tokenMintBAddress: anchor.Address ): boolean ``` - tokenMintAAddress: Token mint that the user wants to trade from - tokenMintBAddress Token mint that the user wants to trade to - Returns: The direction of the swap. True if swapping from A to B. False if swapping from B to A This boolean value will be useful for initializating the enviroment and performing a swap ## initWhirlpool ``` async initWhirlpool(fields: InitWhirlpoolFields) InitWhirlpoolFields = { WhirlpoolsConfig: anchor.Address; tokenMintAAddress: anchor.Address; tokenMintBAddress: anchor.Address; tokenVaultAKeypair: anchor.web3.Keypair; tokenVaultBKeypair: anchor.web3.Keypair; tickSpacing: number; initSqrtPrice: anchor.BN; }; ``` - WhirlpoolsConfig: Address of the WhirlpoolsConfig previously created - tokenMintAAddress: Mint public key for token A - tokenMintBAddress: Mint public key for token B - tokenVaultAKeypair: Keypair of the token A vault for this pool - tokenVaultBKeypair: Keypair of the token B vault for this pool - tickSpacing: The same used in `initConfigAndFeeTier` - iniSqrtPrice: The desired initial sqrt-price for this pool. This value is important because will be used to increase the liquidity of the pool. It can be copied from the existing Whirlpool commented previously, or can be calculated using the `Tick Current Index`. The process will be the following: - Get aToB boolean value - Get `Tick Current Index` - If aToB is true, que `Tick Current Index` will be positive, if is false, the `Tick Current Index` will be negative - Use `tickIndexToSqrtPriceX64` from `PriceMath` class in `@orca-so/whirlpools-sdk` and it will return the `initSqrtPrice` After creating the Whirlpool, to get the Account data you will need to call `getWhirlpool` method: ``` async getWhirpool( config: anchor.web3.PublicKey, tokenMintA: anchor.web3.PublicKey, tokenMintB: anchor.web3.PublicKey, tickSpacing: number ): Promise<Whirlpool> ``` - Config: WhirlpoolConfig account Address This method returns Whirlpool interface. The interface has different methods that return info related with the pool. The most used are: - GetAddress: returns the Whirlpool address - GetData: Return Whirlpool account Data ## initTickArrays ``` async initTickArrays(fields: InitTickArrayFields) InitTickArrayFields = { whirlpool: anchor.Address; tickSpacing: number; tickCurrentIndex: number; aToB: boolean; }; ``` - whirlpool: Address of the Whirlpool previously created - tickSpacing: The same used in `initConfigAndFeeTier` - tickCurrentIndex: This value is in the Whirlpool Data previously created. To get the WhirlpoolData, use the SDK method `getWhirpool`. - aToB: The boolean value previously obtained To get the TickArrays account struct, there is the `getTickArrays` method: ``` async getTickArrays( tickCurrentIndex: number, tickSpacing: number, whirlpoolPubkey: anchor.web3.PublicKey, aToB: boolean ): Promise<TickArray[]> ``` - tickCurrentIndex: obtained from WhirlpoolData - tickSpacing: the previous tick spancing used - whirlpoolPubkey: obtained from getAddress This method returns the 3 tickArrays created with the data of the accounts ## openPosition ``` async openPosition(fields: OpenPositionFields) OpenPositionFields = { whirlpool: anchor.Address; positionMint: anchor.web3.Keypair; tickSpacing: number; tickCurrentIndex: number; aToB: boolean; }; ``` - whirlpool: Address of the Whirlpool previously created - positionMint: PublicKey for the mint token for the Position token - tickSpacing: The same used in `initConfigAndFeeTier` - tickCurrentIndex: The same used in the `initTickArrays` instruction - aToB: The boolean value previously obtained ## increaseLiquidity ``` async increaseLiquidity(fields: IncreaseLiquidityFields) IncreaseLiquidityFields = { whirlpool: anchor.Address; position: anchor.Address; tokenMaxA: anchor.BN; tokenMaxB: anchor.BN; aToB: boolean; }; ``` - whirlpool: Whirlpool address - position: Position address - tokenMaxA: The maximum amount of tokenA allowed to withdraw from the source wallet. - tokenMaxB: The maximum amount of tokenB allowed to withdraw from the source wallet. - aToB Before setting the tokenMaxA and tokenMaxB parameters, you will need the aToB value to know wich token is each one of them and set the value correctly. This two parameters are involved in the final liquidity value to increase. To get an estimate of the liquidity value thay will be added to the pool, you can use the `estimateLiquidityFromTokenAmounts` fuction from `PoolUtil` class in the `@orca-so/whirlpools-sdk`. In the SDK method is calculated and the parameters needed to use that function are obteined there too. ## swapKiToken Now that the enviroment is created, you are able to perform a swap succesfuly. This function is the SDK metod for the `swap_ki_token` instruction. The instruction, invokes the Swap instruction from the Whirlpool program via cpi to trade USDC for Ki tokens. Once the user has the Ki tokens, the same instruction invokes `convert_ki_to_energy` from HabitatManager program and converts the Ki obtanined to energy. Look for the documentation in Habitat Manager for more information about this instruction. ``` async swapKiToken( whirlpoolAddres: anchor.Address, gameAccountUid: string, amount: anchor.BN, aToB: boolean, otherAmountThreshold?: anchor.BN, amountSpecifiedIsInput = false, sqrtPriceLimit = SwapUtils.getDefaultSqrtPriceLimit(aToB) ) ``` - whirlpoolAddres - gameAccountUid: Used in the `convert_ki_to_energy` instruction - amount: The amount of input or output token to swap from - aToB: The direction of the swap - otherAmountThreshold: The maximum/minimum of input/output token to swap into (depending on amount_specified_is_input). If not specified, sets the default value. - amountSpecifiedIsInput: Specifies what the token the parameter `amount`represents. If true, the amount represents the input token of the swap. If false, the amount represents the output token of the swap. Default value is false. - sqrtPriceLimit: The maximum/minimum price the swap will swap to. If not specified, sets the default value