Skip to main content
The Full Sail 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

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
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.

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.
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,
})
Only oSAIL claimed automatically within this transaction. Fees and pool rewards are not.
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,
})
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.
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,
})
Only oSAIL claimed automatically within this transaction. Fees and pool rewards are not.
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,
})
All rewards claimed automatically within this transaction.
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,
})
This method can be used only if position is not staked.
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,
})
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),
})
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),
})
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,
})
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,
})
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,
})
See Aftermath router docs 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(),
})
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,
})
I