4. LP Tracking – Absinthe Docs
Skip to content

4. LP Tracking

Purpose

Track user LP token balances via Transfer events. This emits balanceDelta events that feed into the time-weighted balance (TWB) calculation system, enabling rewards based on liquidity provision duration.

Implementation

if (params.trackLP && log.topics[0] === transferTopic) {
  const { from, to, value } = univ2Abi.events.Transfer.decode(log);
 
  // Handle token outflow (decrease balance)
  await emit.balanceDelta({
    user: from,
    asset: params.poolAddress,
    amount: new Big(value.toString()).neg(),
    activity: 'hold',
  });
 
  // Handle token inflow (increase balance)
  await emit.balanceDelta({
    user: to,
    asset: params.poolAddress,
    amount: new Big(value.toString()),
    activity: 'hold',
  });
}

How Transfer Events Work

ERC-20 Transfer Event

event Transfer(address indexed from, address indexed to, uint256 value);
Topics:
  • topic0: Event signature hash
  • topic1: from address (indexed)
  • topic2: to address (indexed)
  • topic3: value (not indexed, in data)

Automatic Null Address Handling

The Absinthe engine automatically ignores balance delta events for the null address (0x0000000000000000000000000000000000000000). This means you don't need to filter out mint and burn events - the engine handles this automatically.

Balance Delta Logic

Why Two Events?

// When Alice sends 100 tokens to Bob:
// Event 1: Alice's balance decreases by 100
// Event 2: Bob's balance increases by 100
 
// Alice: -100 LP tokens
await emit.balanceDelta({
  user: from,
  asset: params.poolAddress,
  amount: new Big(value.toString()).neg(),
  activity: 'hold',
});
 
// Bob: +100 LP tokens
await emit.balanceDelta({
  user: to,
  asset: params.poolAddress,
  amount: new Big(value.toString()),
  activity: 'hold',
});

Big Number Handling

Why Big Numbers?

// ❌ Wrong: JavaScript numbers lose precision
const amount = value.toString(); // "1000000000000000000000000"
const balance = Number(amount);   // 1e+24 (precision lost!)
 
// ✅ Correct: Use Big.js for precision
import Big from 'big.js';
const amount = new Big(value.toString()); // Exact precision maintained
LP Token Precision:
  • Uniswap V2 LP tokens use 18 decimals
  • 1000000000000000000 = 1 LP token
  • 500000000000000000 = 0.5 LP tokens

Common Pitfalls

// ❌ Incorrect: Direct number conversion
amount: Number(value.toString()) // Precision loss for large numbers
 
// ❌ Incorrect: No negative for outflows
amount: new Big(value.toString()) // Missing .neg() for transfers
 
// ✅ Correct: Proper big number handling
amount: new Big(value.toString()).neg() // For outflows
amount: new Big(value.toString())       // For inflows

Activity Types

activity: 'hold'

Why 'hold'?
  • LP tokens represent ownership in the pool
  • Holding LP tokens = providing liquidity
  • This enables time-weighted rewards for liquidity provision
Other Activity Types:
  • 'swap' - For trading activities
  • 'stake' - For staking tokens
  • 'lend' - For lending activities

Event Deduplication

Why Deterministic Keys Matter

// Each Transfer event should emit unique balance deltas
// The system will aggregate these over time for TWB calculations
Balance Delta Aggregation:
  • User starts with: 0 LP tokens
  • Transfer event 1: +1.0 LP tokens → Balance: 1.0
  • Transfer event 2: -0.5 LP tokens → Balance: 0.5
  • Transfer event 3: +2.0 LP tokens → Balance: 2.5

Real-World Example

Complete Transfer Flow

// User adds liquidity (mint)
{
  user: '0x123...abc',
  asset: '0xpool...address',
  amount: new Big('1000000000000000000'), // +1.0 LP
  activity: 'hold'
}
 
// User removes liquidity (burn)
{
  user: '0x123...abc',
  asset: '0xpool...address',
  amount: new Big('500000000000000000').neg(), // -0.5 LP
  activity: 'hold'
}