Collect Rewards

Claim trading fees and pool rewards from liquidity positions.

Overview

Positions earn two types of rewards:

  • Trading Fees: Earned from swaps in your price range

  • Pool Rewards: Additional incentive tokens from the protocol

Quick Start

// Collect only trading fees
const tx = await sdk.Position.collectFeeTransactionPayload({
  pool_id: '0x...',
  pos_id: '0x...',
  coinTypeA: '0x2::sui::SUI',
  coinTypeB: '0x...::usdc::USDC'
})

// Collect fees + rewards
const tx = await sdk.Rewarder.collectRewarderTransactionPayload({
  pool_id: '0x...',
  pos_id: '0x...',
  coinTypeA: '0x2::sui::SUI',
  coinTypeB: '0x...::usdc::USDC',
  rewarder_coin_types: ['0x...::ferra::FERRA'],
  collect_fee: true
})

Check Claimable Rewards

Trading Fees Only

const fees = await sdk.Position.calculateFee({
  pool_id: poolId,
  pos_id: positionId,
  coinTypeA: '0x2::sui::SUI',
  coinTypeB: '0x...::usdc::USDC'
})

console.log({
  tokenA: fees.feeOwedA,
  tokenB: fees.feeOwedB
})

All Rewards (Fees + Pool Rewards)

// Get position with full reward info
const position = await sdk.Position.getPositionById(positionId, true)

// Check pool rewards
if (position.rewards) {
  position.rewards.forEach(reward => {
    console.log({
      token: reward.coin_type,
      amount: reward.amount_owed
    })
  })
}

// Or use Rewarder module
const pool = await sdk.Pool.getPool(poolId)
const rewards = await sdk.Rewarder.fetchPositionRewarders(pool, positionId)

rewards.forEach(reward => {
  console.log({
    coin: reward.coin_address,
    amount: reward.amount_owed.toString()
  })
})

Collect Trading Fees

const params = {
  pool_id: poolId,
  pos_id: positionId,
  coinTypeA: pool.coinTypeA,
  coinTypeB: pool.coinTypeB
}

// Create transaction
const tx = await sdk.Position.collectFeeTransactionPayload(params)

// Execute
const result = await sdk.fullClient.signAndExecuteTransaction({
  transaction: tx,
  signer: keypair
})

console.log('Fees collected:', result.digest)

Collect Pool Rewards

Collect additional reward tokens (e.g., FERRA tokens):

// Get pool info to check rewarders
const pool = await sdk.Pool.getPool(poolId)
const rewarderTokens = pool.rewarder_infos.map(r => r.coinAddress)

// Collect rewards + fees
const tx = await sdk.Rewarder.collectRewarderTransactionPayload({
  pool_id: poolId,
  pos_id: positionId,
  coinTypeA: pool.coinTypeA,
  coinTypeB: pool.coinTypeB,
  rewarder_coin_types: rewarderTokens,
  collect_fee: true  // Also collect trading fees
})

const result = await sdk.fullClient.signAndExecuteTransaction({
  transaction: tx,
  signer: keypair
})

Batch Collect

Collect from multiple positions efficiently:

const positions = await sdk.Position.getPositionList(userAddress)

// Prepare batch params
const batchParams = []
for (const pos of positions) {
  const pool = await sdk.Pool.getPool(pos.pool)
  
  // Check if position has rewards
  const rewards = await sdk.Rewarder.fetchPositionRewarders(pool, pos.pos_object_id)
  const fees = await sdk.Position.calculateFee({
    pool_id: pos.pool,
    pos_id: pos.pos_object_id,
    coinTypeA: pos.coin_type_a,
    coinTypeB: pos.coin_type_b
  })
  
  const hasRewards = rewards.some(r => r.amount_owed.gt(new BN(0)))
  const hasFees = BigInt(fees.feeOwedA) > 0n || BigInt(fees.feeOwedB) > 0n
  
  if (hasRewards || hasFees) {
    batchParams.push({
      pool_id: pos.pool,
      pos_id: pos.pos_object_id,
      coinTypeA: pos.coin_type_a,
      coinTypeB: pos.coin_type_b,
      rewarder_coin_types: pool.rewarder_infos.map(r => r.coinAddress),
      collect_fee: true
    })
  }
}

// Execute batch collection
if (batchParams.length > 0) {
  const tx = await sdk.Rewarder.batchCollectRewardePayload(batchParams)
  const result = await sdk.fullClient.signAndExecuteTransaction({
    transaction: tx,
    signer: keypair
  })
  console.log(`Collected from ${batchParams.length} positions`)
}

Pool Rewards Info

Check pool reward emissions:

// Get daily emissions for each rewarder
const emissions = await sdk.Rewarder.emissionsEveryDay(poolId)

emissions?.forEach(emission => {
  console.log({
    token: emission.coin_address,
    dailyAmount: emission.emissions
  })
})

// Get total pool rewards for all your positions
const totalRewards = await sdk.Rewarder.fetchPoolRewardersAmount(
  userAddress,
  poolId
)

console.log('Total rewards:', totalRewards)

Complete Example

// 1. Get all positions
const positions = await sdk.Position.getPositionList(userAddress)

// 2. Check each position's rewards
for (const pos of positions) {
  const pool = await sdk.Pool.getPool(pos.pool)
  
  // Check trading fees
  const fees = await sdk.Position.calculateFee({
    pool_id: pos.pool,
    pos_id: pos.pos_object_id,
    coinTypeA: pos.coin_type_a,
    coinTypeB: pos.coin_type_b
  })
  
  // Check pool rewards
  const rewards = await sdk.Rewarder.fetchPositionRewarders(pool, pos.pos_object_id)
  
  console.log(`Position ${pos.pos_object_id}:`)
  console.log(`  Fees: ${fees.feeOwedA} / ${fees.feeOwedB}`)
  rewards.forEach((r, i) => {
    console.log(`  Reward ${i}: ${r.amount_owed} ${r.coin_address}`)
  })
  
  // Collect if has rewards
  const hasRewards = rewards.some(r => r.amount_owed.gt(new BN(0)))
  const hasFees = BigInt(fees.feeOwedA) > 0n || BigInt(fees.feeOwedB) > 0n
  
  if (hasRewards || hasFees) {
    const tx = await sdk.Rewarder.collectRewarderTransactionPayload({
      pool_id: pos.pool,
      pos_id: pos.pos_object_id,
      coinTypeA: pos.coin_type_a,
      coinTypeB: pos.coin_type_b,
      rewarder_coin_types: pool.rewarder_infos.map(r => r.coinAddress),
      collect_fee: true
    })
    
    const result = await sdk.fullClient.signAndExecuteTransaction({
      transaction: tx,
      signer: keypair
    })
    
    console.log('  Collected:', result.digest)
  }
}

Important Notes

  • Trading fees accumulate from swaps in your price range

  • Pool rewards are additional incentives (e.g., FERRA tokens)

  • Use collect_fee: true to collect both in one transaction

  • Rewards are sent directly to sender address

  • Some operations auto-collect rewards (add/remove liquidity)

  • Batch collection saves gas for multiple positions

Last updated