> For the complete documentation index, see [llms.txt](https://docs.ferra.ag/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ferra.ag/integration/damm/typescript-sdk/fee-and-reward.md).

# Fee & Reward

### Overview

Positions earn two types of rewards:

* **Trading Fees**: Earned from swaps in your price range
* **Pool Rewards**: Additional incentive tokens from the protocol

***

### Check Pending Rewards

#### Trading Fees Only

```typescript
// Using Rewarder module for fee calculation
const position = await sdk.Position.getPositionById(positionId, false)
const pool = await sdk.Pool.getPool(position.pool)

const fees = await sdk.Rewarder.fetchPosFeeAmount([{
  poolAddress: pool.poolAddress,
  positionId: position.pos_object_id,
  coinTypeA: pool.coinTypeA,
  coinTypeB: pool.coinTypeB
}])

if (fees.length > 0) {
  console.log({
    tokenA: fees[0].feeOwedA.toString(),
    tokenB: fees[0].feeOwedB.toString()
  })
}
```

#### All Rewards (Fees + Pool Rewards)

```typescript
// 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()
  })
})
```

#### Batch Fetch Position Fees

```typescript
// Multiple positions
const positionIds = ['0x1...', '0x2...']
const allFees = await sdk.Rewarder.batchFetchPositionFees(positionIds)

// Access fees for each position
for (const [posId, fees] of Object.entries(allFees)) {
  console.log(`Position ${posId}:`)
  console.log(`  Fee A: ${fees.feeOwedA.toString()}`)
  console.log(`  Fee B: ${fees.feeOwedB.toString()}`)
}
```

#### Pool Rewards Info

Check pool reward emissions:

```typescript
// 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)
```

***

### Collect Trading Fees

```typescript
const pool = await sdk.Pool.getPool(poolId)

const params = {
  pool_id: pool.poolAddress,
  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):

```typescript
// Get pool info to check rewarders
const pool = await sdk.Pool.getPool(poolId)
const rewarderTokens = pool.rewarderInfos.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:

```typescript
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.Rewarder.batchFetchPositionFees([pos.pos_object_id])

  const hasRewards = rewards.some(r => r.amount_owed.gt(new BN(0)))
  const positionFee = fees[pos.pos_object_id]
  const hasFees = positionFee && (positionFee.feeOwedA.gt(new BN(0)) || positionFee.feeOwedB.gt(new BN(0)))

  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.rewarderInfos.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`)
}
```

***

### Complete Example

```typescript
// 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 using Rewarder module
  const feeResult = await sdk.Rewarder.fetchPosFeeAmount([{
    poolAddress: pool.poolAddress,
    positionId: pos.pos_object_id,
    coinTypeA: pool.coinTypeA,
    coinTypeB: pool.coinTypeB
  }])

  // Check pool rewards
  const rewards = await sdk.Rewarder.fetchPositionRewarders(pool, pos.pos_object_id)

  console.log(`Position ${pos.pos_object_id}:`)
  if (feeResult.length > 0) {
    console.log(`  Fees: ${feeResult[0].feeOwedA.toString()} / ${feeResult[0].feeOwedB.toString()}`)
  }
  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 = feeResult.length > 0 && (feeResult[0].feeOwedA.gt(new BN(0)) || feeResult[0].feeOwedB.gt(new BN(0)))

  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.rewarderInfos.map(r => r.coinAddress),
      collect_fee: true
    })

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

    console.log('  Collected:', result.digest)
  }
}
```

***

### Partner Referral Fees

Partners who integrate Ferra swaps can earn referral fees. Use these methods to check and claim partner fees.

#### Check Partner Fee Balance

```typescript
const partnerObjectId = '0xPartner...'

const feeBalances = await sdk.Pool.getPartnerRefFeeAmount(partnerObjectId)

feeBalances.forEach(asset => {
  console.log({
    coinType: asset.coinAddress,
    balance: asset.balance.toString()
  })
})
```

#### Claim Partner Fees

```typescript
const tx = await sdk.Pool.claimPartnerRefFeePayload(
  '0xPartnerCapId...',   // Partner capability NFT
  '0xPartnerObjectId...',  // Partner object
  '0x2::sui::SUI'        // Coin type to claim
)

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

console.log('Partner fees claimed:', result.digest)
```

***

### APR Calculation

Estimate APR for pools and individual positions.

#### Pool APR

```typescript
import { estPoolAPR } from '@ferra-labs/damm'
import BN from 'bn.js'

const apr = estPoolAPR(
  new BN('1000000'),      // preBlockReward: reward per block
  new BN('150'),          // rewardPrice: reward token price (cents)
  new BN('50000'),        // totalTradingFee: total fees collected
  new BN('10000000')      // totalLiquidityValue: pool TVL
)

console.log('Pool APR:', apr.toString())
```

#### Position APR (Delta Method)

Estimate APR for a specific position based on its price range and pool data:

```typescript
import { estPositionAPRWithDeltaMethod } from '@ferra-labs/damm'
import BN from 'bn.js'

const pool = await sdk.Pool.getPool(poolId)
const position = await sdk.Position.getPositionById(positionId)

const result = estPositionAPRWithDeltaMethod(
  pool.currentTickIndex,           // currentTickIndex
  position.tick_lower_index,       // lowerTickIndex
  position.tick_upper_index,       // upperTickIndex
  new BN(pool.currentSqrtPrice),   // currentSqrtPriceX64
  new BN(pool.liquidity),          // poolLiquidity
  9,                               // decimalsA
  6,                               // decimalsB
  9,                               // decimalsRewarder0
  9,                               // decimalsRewarder1
  9,                               // decimalsRewarder2
  pool.feeRate,                    // feeRate
  '100000000',                     // amountA (position)
  '50000000',                      // amountB (position)
  pool.coinAmountA,                // poolAmountA
  pool.coinAmountB,                // poolAmountB
  '1000000',                       // swapVolume (7-day)
  '500000',                        // poolRewarders0 (7-day emissions)
  '0',                             // poolRewarders1
  '0',                             // poolRewarders2
  '1.5',                           // coinAPrice (USD)
  '1.0',                           // coinBPrice (USD)
  '0.5',                           // rewarder0Price (USD)
  '0',                             // rewarder1Price (USD)
  '0'                              // rewarder2Price (USD)
)

console.log({
  feeAPR: result.feeAPR.toString(),
  rewarder0APR: result.posRewarder0APR.toString(),
  rewarder1APR: result.posRewarder1APR.toString(),
  rewarder2APR: result.posRewarder2APR.toString()
})
```

#### Result Type

```typescript
type estPosAPRResult = {
  feeAPR: Decimal         // APR from trading fees
  posRewarder0APR: Decimal // APR from rewarder slot 0
  posRewarder1APR: Decimal // APR from rewarder slot 1
  posRewarder2APR: Decimal // APR from rewarder slot 2
}
```

***

### 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
* Partner fees require a partner capability NFT to claim
* APR calculations use 7-day data for accuracy
