> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fullsail.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# Full Sail SDK

The [**Full Sail SDK**](https://www.npmjs.com/package/@fullsailfinance/sdk) provides developers with a simple and efficient interface for interacting with the Full Sail protocol. It enables seamless integration of swaps, liquidity management, and governance interactions into external applications, analytics tools, or automated strategies.

## Installation

Install the SDK using npm:

```
$ npm i @fullsailfinance/sdk
```

Install the SDK using yarn:

```
$ yarn add @fullsailfinance/sdk
```

## Configuration

```javascript theme={null}
import { initFullSailSDK } from '@fullsailfinance/sdk'

const fullSailSDK = initFullSailSDK({
  network: 'mainnet-production',
  // You can also provide your own full node URL and simulation account. It's optional.
  fullNodeUrl: 'https://...',
  simulationAccount: '0x...',
})
```

After you have connected the wallet, you should set `senderAddress` to your sdk instance

```javascript theme={null}
fullSailSDK.senderAddress = '0x...'
// or
fullSailSDK.setSenderAddress('0x...')
```

## Key Concepts

### **Gauge**

A smart contract that manages staked positions rewards and oSAIL token distribution. Core functions:

* **Position Staking Management**: Tracks staked positions, calculates rewards, and enables withdrawal
* **Reward & oSAIL Distribution**: Distributes rewards and oSAIL tokens to staked positions. New oSAIL tokens are issued weekly for each epoch
* **Reward Calculation**: Calculates earned oSAIL rewards based on staked liquidity and time, and processes reward claims to position owners
* **Fee Collection**: Collects and manages fees generated by the associated liquidity pool

### **Ticks**

Discrete price points that define the boundaries of liquidity ranges. Important considerations:

* Each tick represents a specific price ratio
* Ticks are spaced at constant intervals determined by the pool's tick spacing

### **Pool**

Initially created without a gauge. It can be added later to enable reward distribution.

There are two pool entities available through the SDK:

**Chain Pool** (`Pool.getByIdFromChain()`): Contains real-time data directly from the blockchain. Data from this entity is always relevant.

Some core/unique properties:

* `currentTickIndex`: The tick corresponding to the current price of the pool (determines which liquidity positions are currently active)
* `rewardCoinsInfo`: List of reward coins available for this pool
* `currentSqrtPrice`: Current sqrt price of the pool

**Pool** (`Pool.getById()`): Contains calculated data and metadata from the backend which can be convinient for frontend. It can contain same fields as ChainPool but they may be outdated by a few minutes, especially those that change frequently.

Some core/unique properties:

* `gauge_id`: Unique identifier for gauge contract related to this pool

Use backend pool for stable metadata and `gauge_id`, use chain pool for relevant current price and reward data.

### **Position**

Represents a range of prices where you provide liquidity to a pool. If gauge exists for this pool, position should be staked, otherwise it will not receive rewards.

Some core properties:

* `tick_lower`: The lower bound of your price range (minimum price where your liquidity is active)
* `tick_upper`: The upper bound of your price range (maximum price where your liquidity is active)
* `liquidity`: The amount of liquidity provided in this price range
* `stake_info`: Information about the position stake object within the gauge. Can be undefined if position not staked or no gauge exists for this pool.

### **Position Rewards**

Different position states receive different types of rewards:

* **Position in pool without gauge**: Receives pool fees and pool rewards
* **Unstaked position in pool with gauge**: Receives nothing
* **Staked position in pool with gauge**: Receives oSAIL tokens and pool rewards

### **oSAIL**

oSAIL is the emissions token distributed to staked positions. Each epoch has its own oSAIL token with a specific expiration date - 5 weeks from the start of the epoch. It offers two possible paths: lock it into veSAIL to participate in governance and earn trading fees, or redeem it for liquid SAIL at 50% of the current spot price at time of redemption, paid in USDC. Expired oSAIL can be only locked into veSAIL.

### **Lock (veSAIL)**

Represents voting power and used only for voting. Minted by locking SAIL or oSAIL for a fixed duration. Lock amount multiplied by lock duration determines voting power. `isPermanent` option commits to the longest available lock period for maximum voting power.

Some core properties:

* `permanent`: whether lock is permanent or not
* `voting_power`: current voting power provided by this lock. Reduces slowly over time if lock is not permanent
* `is_voting_onchain`: whether lock is used for voting at current epoch
* `amount`: amount of SAIL locked

Locks are transferable, supports merging, splitting, increasing amount/duration. Liquid SAIL unlocks at lock expiration.

### **Epoch**

7-day cycle during which veSAIL holders vote and predict trading volumes for pools.

### **Voting**

veSAIL holders can vote and predict trading volumes for pools for the next epoch. Only pools with gauge can be voted.

Voters earn from two sources:

* **Trading fees** from voted pools, distributed by prediction accuracy and allocated voting power.

## Usage examples

If method name ends with `...Transaction`, it returns a transaction that should be signed and executed using your sui client or wallet kit.

<Accordion title="Create Position">
  ```javascript theme={null}
  const poolId = '0x0...'

  const amountA = 1000000n
  const fixedAmountA = true
  const roundUp = true
  // 1%
  const slippage = Percentage.fromNumber(1)

  const pool = await fullSailSDK.Pool.getById(poolId)
  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)

  // get the nearest tick indexes based on current price
  const tickLower = TickMath.getPrevInitializableTickIndex(chainPool.currentTickIndex, chainPool.tickSpacing)
  const tickUpper = TickMath.getNextInitializableTickIndex(chainPool.currentTickIndex, chainPool.tickSpacing)

  // Calculate the opposite coin amount based on the first coin amount and tick range
  // This ensures proper liquidity ratio within the specified price range, including slippage
  const { maxAmountB } = ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts(
    tickLower,
    tickUpper,
    amountA, // change to amountB if you want to calculate maxAmountA based on amountB
    fixedAmountA, // change to false if you want to calculate maxAmountA based on amountB
    roundUp,
    slippage.toCoefficient(),
    chainPool.currentSqrtPrice,
  )

  const transaction = await fullSailSDK.Position.openTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    tickLower,
    tickUpper,
    amountA,
    amountB: maxAmountB,
    slippage,
    fixedAmountA,
    currentSqrtPrice: chainPool.currentSqrtPrice,
    // if gaugeId provided, position will be staked automatically
    gaugeId: pool.gauge_id,
  })
  ```
</Accordion>

<Accordion title="Add Liquidity To Position">
  Only oSAIL claimed automatically within this transaction. Fees and pool rewards are not.

  ```javascript theme={null}
  const poolId = '0x0...'
  const positionId = '0x0...'

  const amountA = 1000000n
  const fixedAmountA = true
  const roundUp = true
  // 1%
  const slippage = Percentage.fromNumber(1)

  const pool = await fullSailSDK.Pool.getById(poolId)
  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)
  const position = await fullSailSDK.Position.getById(positionId)
  const currentEpochOSail = await fullSailSDK.Coin.getCurrentEpochOSail()

  const { maxAmountB } = ClmmPoolUtil.estLiquidityAndCoinAmountFromOneAmounts(
    position.tick_lower,
    position.tick_upper,
    amountA,
    fixedAmountA,
    roundUp,
    slippage.toCoefficient(),
    chainPool.currentSqrtPrice,
  )

  const transaction = await sdk.Position.addLiquidityTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    positionId,
    tickLower: position.tick_lower,
    tickUpper: position.tick_upper,
    amountA,
    amountB: maxAmountB,
    slippage,
    fixedAmountA,
    currentSqrtPrice: chainPool.currentSqrtPrice,
    // params below are required only if position is staked
    gaugeId: pool.gauge_id,
    oSailCoinType: currentEpochOSail.address,
    positionStakeId: position.stake_info?.id,
  })
  ```
</Accordion>

<Accordion title="Stake Position">
  This method can be used only if position is created before gauge is added to the pool or if `gaugeId` was not provided when creating the position via `Position.openTransaction()`. Unstaked positions within a pool with gauge will not receive rewards. Only fees claimed automatically within this transaction. Pool rewards are not.

  ```javascript theme={null}
  const poolId = '0x0...'
  const positionId = '0x0...'

  const position = await fullSailSDK.Position.getById(positionId)
  const pool = await fullSailSDK.Pool.getById(poolId)

  const transaction = await sdk.Position.stakeTransaction({
    coinTypeA: pool.token_a.address,
    coinTypeB: pool.token_b.address,
    poolId: pool.address,
    positionId: position.id,
    gaugeId: pool.gauge_id,
  })
  ```
</Accordion>

<Accordion title="Remove Liquidity From Position">
  Only oSAIL claimed automatically within this transaction. Fees and pool rewards are not.

  ```javascript theme={null}
  const poolId = '0x0...'
  const positionId = '0x0...'

  const liquidity = 1000000n
  // 1%
  const slippage = Percentage.fromNumber(1)

  const pool = await fullSailSDK.Pool.getById(poolId)
  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)
  const position = await fullSailSDK.Position.getById(positionId)
  const currentEpochOSail = await fullSailSDK.Coin.getCurrentEpochOSail()

  const transaction = await sdk.Position.removeLiquidityTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    positionId,
    tickLower: position.tick_lower,
    tickUpper: position.tick_upper,
    currentSqrtPrice: chainPool.currentSqrtPrice,
    liquidity,
    slippage,
    // params below are required only if position is staked
    gaugeId: pool.gauge_id,
    oSailCoinType: currentEpochOSail.address,
    positionStakeId: position.stake_info?.id,
  })
  ```
</Accordion>

<Accordion title="Close Position">
  All rewards claimed automatically within this transaction.

  ```javascript theme={null}
  const poolId = '0x0...'
  const positionId = '0x0...'

  const liquidity = 1000000n
  // 1%
  const slippage = Percentage.fromNumber(1)

  const pool = await fullSailSDK.Pool.getById(poolId)
  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)
  const position = await fullSailSDK.Position.getById(positionId)
  const currentEpochOSail = await fullSailSDK.Coin.getCurrentEpochOSail()

  const transaction = await sdk.Position.closeTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    positionId,
    tickLower: position.tick_lower,
    tickUpper: position.tick_upper,
    currentSqrtPrice: chainPool.currentSqrtPrice,
    liquidity,
    slippage,
    // You must provide the exact reward coin list to claim all available rewards.
    rewardCoinTypes: chainPool.rewardCoinsInfo.map(({ coinType }) => coinType),
    // params below are required only if position is staked
    gaugeId: pool.gauge_id,
    oSailCoinType: currentEpochOSail.address,
    positionStakeId: position.stake_info?.id,
  })
  ```
</Accordion>

<Accordion title="Claim Fee">
  This method can be used only if position is not staked.

  ```javascript theme={null}
  const poolId = '0x0...'
  const positionId = '0x0...'

  const pool = await fullSailSDK.Pool.getById(poolId)

  const transaction = await sdk.Position.claimFeeTransaction({
    coinTypeA: pool.token_a.address,
    coinTypeB: pool.token_b.address,
    poolId,
    positionId,
  })
  ```
</Accordion>

<Accordion title="Claim Unstaked Position Rewards">
  This method can be used only if position is not staked.

  ```
  const poolId = '0x0...'
  const positionId = '0x0...'

  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)

  const transaction = await fullSailSDK.Position.claimUnstakedPoolRewardsTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    positionId,
    rewardCoinTypes: chainPool.rewardCoinsInfo.map(({ coinType }) => coinType),
  })
  ```
</Accordion>

<Accordion title="Claim All Unstaked Position Rewards">
  This method claims both fee and pool rewards for unstaked position.

  ```
  const poolId = '0x0...'
  const positionId = '0x0...'

  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)

  const transaction = await sdk.Position.claimFeeAndUnstakedPoolRewardsTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    positionId,
    rewardCoinTypes: chainPool.rewardCoinsInfo.map(({ coinType }) => coinType),
  })
  ```
</Accordion>

<Accordion title="Claim oSAIL">
  This method can be used only if position is staked.

  ```
  const poolId = '0x0...'
  const positionId = '0x0...'

  const pool = await fullSailSDK.Pool.getById(poolId)
  const position = await fullSailSDK.Position.getById(positionId)
  const currentEpochOSail = await fullSailSDK.Coin.getCurrentEpochOSail()

  const transaction = await sdk.Position.claimOSailTransaction({
    coinTypeA: pool.token_a.address,
    coinTypeB: pool.token_b.address,
    poolId,
    positionStakeId: position.stake_info.id,
    oSailCoinType: currentEpochOSail.address,
    gaugeId: pool.gauge_id,
  })
  ```
</Accordion>

<Accordion title="Claim Staked Position Rewards">
  This method can be used only if position is staked.

  ```
  const poolId = '0x0...'
  const positionId = '0x0...'

  const pool = await fullSailSDK.Pool.getById(poolId)
  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)
  const position = await fullSailSDK.Position.getById(positionId)

  const transaction = await sdk.Position.claimStakedPoolRewardsTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    positionStakeId: position.stake_info.id,
    rewardCoinTypes: chainPool.rewardCoinsInfo.map(({ coinType }) => coinType),
    gaugeId: pool.gauge_id,
  })
  ```
</Accordion>

<Accordion title="Claim All Staked Position Rewards">
  This method claims both oSAIL and pool rewards for staked position.

  ```
  const poolId = '0x0...'
  const positionId = '0x0...'

  const pool = await fullSailSDK.Pool.getById(poolId)
  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)
  const position = await fullSailSDK.Position.getById(positionId)
  const currentEpochOSail = await fullSailSDK.Coin.getCurrentEpochOSail()

  const transaction = await sdk.Position.claimOSailAndStakedPoolRewardsTransaction({
    coinTypeA: chainPool.coinTypeA,
    coinTypeB: chainPool.coinTypeB,
    poolId,
    rewardCoinTypes: chainPool.rewardCoinsInfo.map(({ coinType }) => coinType),
    positionStakeId: position.stake_info.id,
    gaugeId: pool.gauge_id,
    oSailCoinType: currentEpochOSail?.address,
  })
  ```
</Accordion>

<Accordion title="Swap">
  See [**Aftermath router docs**](https://docs.aftermath.finance/developers/aftermath-ts-sdk/products/router#getcompletetraderoutegivenamountin) for more details.

  ```
  const coinInType = '0x0...'
  const coinOutType = '0x0...'
  const coinInAmount = 1000000n
  const slippage = Percentage.fromNumber(1)

  // getCompleteTradeRouteGivenAmountIn method from Aftermath router
  const completeRoute = await fullSailSDK.Swap.getSwapRoute({
    coinInType,
    coinOutType,
    coinInAmount,
  })

  // getTransactionForCompleteTradeRoute method from Aftermath router
  const transaction = await fullSailSDK.Swap.swapRouterTransaction({
    completeRoute,
    slippage: slippage.toCoefficient(),
  })
  ```

  Swaps coins directly through smart contract.

  ```
  const poolId = '0x0...'
  const coinInType = '0x0...'
  const coinOutType = '0x0...'

  const slippage = Percentage.fromNumber(1)
  const amount = 1000000n
  const byAmountIn = true

  const chainPool = await fullSailSDK.Pool.getByIdFromChain(poolId)
  const coinIn = await fullSailSDK.Coin.getByType(coinInType)
  const coinOut = await fullSailSDK.Coin.getByType(coinOutType)

  // checking swap direction
  const isAtoB = chainPool.coinTypeA === coinInType

  // calculates estimated amounts, price after swap, and returns some of method params as swap params for convinience
  const presSwap = await fullSailSDK.Swap.preSwap({
    coinTypeA: isAtoB ? coinInType : coinOutType,
    coinTypeB: isAtoB ? coinOutType : coinInType,
    decimalsA: isAtoB ? coinIn.decimals : coinOut.decimals,
    decimalsB: isAtoB ? coinOut.decimals : coinIn.decimals,
    poolId,
    amount,
    byAmountIn,
    isAtoB,
    currentSqrtPrice: chainPool.currentSqrtPrice,
  })

  const transaction = await fullSailSDK.Swap.swapTransaction({
    amount,
    amountLimit: byAmountIn ? presSwap.estimatedAmountOut : presSwap.estimatedAmountIn,
    slippage,
    ...presSwap.swapParams,
  })
  ```
</Accordion>

<Accordion title="Create Lock">
  Creates lock using SAIL.

  ```
  // 1 SAIL
  const amount = 1000000n
  // 4 years
  const durationDays = 365 * 4

  const transaction = await fullSailSDK.Lock.createLockTransaction({
    amount,
    isPermanent: true,
    durationDays,
  })
  ```

  Creates lock using oSAIL.

  ```
  const oSailCoinType = '0x0...'

  // 1 oSAIL
  const amount = 1000000n
  // 4 years
  const durationDays = 365 * 4

  const transaction = await fullSailSDK.Lock.createLockFromOSailTransaction({
    amount,
    oSailCoinType,
    durationDays,
    isPermanent: true,
  })
  ```
</Accordion>

<Accordion title="Claim oSAIL and create lock">
  Combines `Position.claimOSailTransaction()` and `Lock.createLockFromOSailTransaction()` for convinience.

  ```
  const poolId = '0x0...'
  const positionId = '0x0...'

  const pool = await fullSailSDK.Pool.getById(poolId)
  const position = await fullSailSDK.Position.getById(positionId)
  const currentEpochOSail = await fullSailSDK.Coin.getCurrentEpochOSail()

  // 4 years
  const durationDays = 365 * 4

  const transaction = await fullSailSDK.Lock.claimOSailAndCreateLockTransaction({
    coinTypeA: pool.token_a.address,
    coinTypeB: pool.token_b.address,
    poolId,
    gaugeId: pool.gauge_id,
    positionStakeId: position.stake_info.id,
    oSailCoinType: currentEpochOSail.address,
    durationDays,
    isPermanent: true,
  })
  ```
</Accordion>

<Accordion title="Increase lock amount">
  Increases lock by provided SAIL amount.

  ```
  const lockId = '0x0...'

  // 1 SAIL
  const amount = 1000000n

  const transaction = await fullSailSDK.Lock.increaseAmountTransaction({
    lockId,
    amount,
  })
  ```
</Accordion>

<Accordion title="Merge locks">
  Merges two locks into one. If one of the locks is used for voting, votes from this lock will be reset, and user will need to vote again.

  ```
  const fromLockId = '0x0...'
  const toLockId = '0x0...'

  const transaction = await fullSailSDK.Lock.mergeTransaction({
    fromLockId,
    toLockId,
    isFromLockVoted: true,
    isToLockVoted: false,
  })
  ```
</Accordion>

<Accordion title="Split lock">
  Splits lock into two locks by SAIL amount. If lock is used for voting, votes from this lock will be reset, and user will need to vote again.

  ```
  const lockId = '0x0...'

  // 1 SAIL
  const amount = 1000000n

  const transaction = await fullSailSDK.Lock.splitTransaction({
    lockId,
    amount,
    isVoted: true,
  })
  ```
</Accordion>

<Accordion title="Transfer lock">
  Transfers lock to another wallet.

  ```
  const lockId = '0x0...'
  const receiver = '0x0...'

  const transaction = await fullSailSDK.Lock.transferTransaction({
    lockId,
    receiver,
  })
  ```
</Accordion>

<Accordion title="Increase lock duration">
  ```
  const lockId = '0x0...'
  // 4 years
  const durationDays = 365 * 4

  const transaction = await fullSailSDK.Lock.increaseDurationTransaction({
    lockId,
    durationDays,
  })
  ```
</Accordion>

<Accordion title="Enable/disable isPermanent">
  Enables `isPermanent` flag for lock.

  ```
  const lockId = '0x0...'

  const transaction = await fullSailSDK.Lock.enablePermanentTransaction({
    lockId,
  })
  ```

  Disables `isPermanent` flag for lock.

  ```
  const lockId = '0x0...'

  const transaction = await fullSailSDK.Lock.disablePermanentTransaction({
    lockId,
  })
  ```
</Accordion>

<Accordion title="Vote">
  Votes using all locks.

  `weight` is in abstract units to calculate voting power ratio. It sum can be any value and will be used as 100%. For example you can provide weights `[20, 80]` or `[1, 1]` and it will work fine. In case of `[20, 80]` total weight is 100 (similarly to 100%). First pool will receve 20/100 (20%) of voting power and second pool will receive 80/100 (80%) of voting power. In case of `[1, 1]` total weight is 2. First pool will receve 1/2 (50%) of voting power and second pool will receive 1/2 (50%) of voting power.

  `volume` is predicted volume of pool for next epoch in USD with decimals 6.

  ```
  const lockId1 = '0x0...'
  const lockId2 = '0x0...'
  const lockId3 = '0x0...'

  const poolId1 = '0x0...'
  const poolId2 = '0x0...'

  const weight1 = 20n
  const weight2 = 80n

  // 1 USD
  const volume1 = 1000000n
  // 2 USD
  const volume2 = 2000000n

  const transaction = await fullSailSDK.Lock.batchVoteTransaction({
    // locks will be used for voting
    lockIds: [lockId1, lockId2, lockId3],
    // each array item is a vote for pool
    votes: [
      { poolId: poolId1, weight: weight1, volume: volume1 },
      { poolId: poolId2, weight: weight2, volume: volume2 },
    ],
  })
  ```
</Accordion>
