Aller au contenu

TraderJoe V2

Connector for TraderJoe V2 Liquidity Book DEX.

almanak.connectors.traderjoe_v2

TraderJoe Liquidity Book V2 Connector.

This module provides the TraderJoe V2 adapter for executing swaps and managing liquidity positions on TraderJoe V2's Liquidity Book.

TraderJoe V2 Architecture: - LBRouter: Main entry point for swaps and liquidity operations - LBFactory: Creates and manages LBPair pools - LBPair: Liquidity pool with discrete bins (not continuous ticks)

Key Concepts: - Bin: Discrete price point (unlike Uniswap V3's continuous ticks) - BinStep: Fee tier in basis points between bins (e.g., 20 = 0.2%) - Fungible LP Tokens: ERC1155-like tokens for each bin (no NFTs)

Supported chains: - Avalanche (Chain ID: 43114) - Arbitrum One (Chain ID: 42161) - BNB Smart Chain (Chain ID: 56) - Ethereum (Chain ID: 1)

Example

from almanak.connectors.traderjoe_v2 import TraderJoeV2Adapter, TraderJoeV2Config

config = TraderJoeV2Config( chain="avalanche", wallet_address="0x...", rpc_url="https://api.avax.network/ext/bc/C/rpc", ) adapter = TraderJoeV2Adapter(config)

Get a swap quote

quote = adapter.get_swap_quote( token_in="WAVAX", token_out="USDC", amount_in=Decimal("1.0"), bin_step=20, )

Use SDK for lower-level operations

from almanak.connectors.traderjoe_v2 import TraderJoeV2SDK

sdk = TraderJoeV2SDK(chain="avalanche", rpc_url="https://api.avax.network/ext/bc/C/rpc") pool = sdk.get_pool_address(wavax_addr, usdc_addr, bin_step=20)

LiquidityPosition dataclass

LiquidityPosition(
    pool_address: str,
    token_x: str,
    token_y: str,
    bin_step: int,
    bin_ids: list[int],
    balances: dict[int, int],
    amount_x: int,
    amount_y: int,
    active_bin: int,
)

Represents a liquidity position in TraderJoe V2.

属性:

名称 类型 描述
pool_address str

Address of the LBPair pool

token_x str

Address of token X

token_y str

Address of token Y

bin_step int

Bin step of the pool

bin_ids list[int]

List of bin IDs where position has liquidity

balances dict[int, int]

Dict mapping bin ID to LB token balance

amount_x int

Total amount of token X in position

amount_y int

Total amount of token Y in position

active_bin int

Current active bin ID of the pool

SwapQuote dataclass

SwapQuote(
    token_in: str,
    token_out: str,
    amount_in: Decimal,
    amount_out: Decimal,
    bin_step: int,
    price: Decimal,
    price_impact: Decimal,
    path: list[str],
    gas_estimate: int = DEFAULT_GAS_ESTIMATES["swap"],
)

Quote for a swap operation.

属性:

名称 类型 描述
token_in str

Input token symbol or address

token_out str

Output token symbol or address

amount_in Decimal

Amount of input token (in token units)

amount_out Decimal

Expected amount of output token (in token units)

bin_step int

Bin step used for the swap

price Decimal

Execution price (amount_out / amount_in)

price_impact Decimal

Estimated price impact as percentage

path list[str]

Token path for the swap

gas_estimate int

Estimated gas for the transaction

SwapResult dataclass

SwapResult(
    success: bool,
    tx_hash: str | None = None,
    token_in: str | None = None,
    token_out: str | None = None,
    amount_in: Decimal | None = None,
    amount_out: Decimal | None = None,
    gas_used: int | None = None,
    block_number: int | None = None,
    timestamp: datetime | None = None,
    error: str | None = None,
)

Result of an executed swap.

属性:

名称 类型 描述
success bool

Whether the swap succeeded

tx_hash str | None

Transaction hash

token_in str | None

Input token

token_out str | None

Output token

amount_in Decimal | None

Amount of input token used

amount_out Decimal | None

Amount of output token received

gas_used int | None

Actual gas used

block_number int | None

Block number of the transaction

timestamp datetime | None

Timestamp of the transaction

error str | None

Error message if failed

SwapType

Bases: StrEnum

Type of swap to execute.

TraderJoeV2Adapter

TraderJoeV2Adapter(
    config: TraderJoeV2Config,
    token_resolver: TokenResolver | None = None,
)

Adapter for TraderJoe Liquidity Book V2 protocol.

Provides high-level methods for: - Token swaps (exact input) - Liquidity management (add/remove) - Position queries - Quote generation

The adapter handles token resolution, slippage calculations, and transaction building internally.

Example

config = TraderJoeV2Config( chain="avalanche", wallet_address="0x...", rpc_url="https://api.avax.network/ext/bc/C/rpc", ) adapter = TraderJoeV2Adapter(config)

Get quote

quote = adapter.get_swap_quote("WAVAX", "USDC", Decimal("1.0"), bin_step=20)

Execute swap

result = adapter.swap_exact_input("WAVAX", "USDC", Decimal("1.0"), bin_step=20)

Initialize the adapter.

参数:

名称 类型 描述 默认
config TraderJoeV2Config

Adapter configuration

必需
token_resolver TokenResolver | None

Optional TokenResolver instance. If None, uses singleton.

None

引发:

类型 描述
TraderJoeV2SDKError

If chain is not supported or connection fails

resolve_token_address

resolve_token_address(token: str) -> str

Resolve a token symbol or address to a checksummed address using TokenResolver.

参数:

名称 类型 描述 默认
token str

Token symbol (e.g., "WAVAX") or address

必需

返回:

类型 描述
str

Checksummed token address

引发:

类型 描述
TokenResolutionError

If token cannot be resolved

get_token_decimals

get_token_decimals(token: str) -> int

Get decimals for a token using TokenResolver.

参数:

名称 类型 描述 默认
token str

Token symbol or address

必需

返回:

类型 描述
int

Token decimals

引发:

类型 描述
TokenResolutionError

If decimals cannot be determined

to_wei

to_wei(amount: Decimal, token: str) -> int

Convert token amount to wei (smallest unit).

参数:

名称 类型 描述 默认
amount Decimal

Amount in token units

必需
token str

Token symbol or address

必需

返回:

类型 描述
int

Amount in wei

from_wei

from_wei(amount: int, token: str) -> Decimal

Convert wei to token amount.

参数:

名称 类型 描述 默认
amount int

Amount in wei

必需
token str

Token symbol or address

必需

返回:

类型 描述
Decimal

Amount in token units

get_swap_quote

get_swap_quote(
    token_in: str,
    token_out: str,
    amount_in: Decimal,
    bin_step: int = 20,
) -> SwapQuote

Get a quote for a swap.

参数:

名称 类型 描述 默认
token_in str

Input token symbol or address

必需
token_out str

Output token symbol or address

必需
amount_in Decimal

Amount of input token

必需
bin_step int

Bin step for the pair (default 20 = 0.2%)

20

返回:

类型 描述
SwapQuote

SwapQuote with expected output and price info

引发:

类型 描述
PoolNotFoundError

If pool doesn't exist

build_swap_transaction

build_swap_transaction(
    token_in: str,
    token_out: str,
    amount_in: Decimal,
    bin_step: int = 20,
    slippage_bps: int | None = None,
    recipient: str | None = None,
    *,
    quote: SwapQuote | None = None,
) -> TransactionData

Build a swap transaction without executing it.

参数:

名称 类型 描述 默认
token_in str

Input token symbol or address

必需
token_out str

Output token symbol or address

必需
amount_in Decimal

Amount of input token

必需
bin_step int

Bin step for the pair

20
slippage_bps int | None

Slippage tolerance in basis points

None
recipient str | None

Recipient address (default: wallet_address)

None
quote SwapQuote | None

Optional pre-computed SwapQuote to avoid a second on-chain getSwapOut call. Callers that already fetched a quote (e.g. the IntentCompiler persisting expected_output_human for realized-slippage tracking) should pass it here so the same quote shapes both amount_out_min and the metadata baseline.

None

返回:

类型 描述
TransactionData

TransactionData ready for signing and execution

swap_exact_input

swap_exact_input(
    token_in: str,
    token_out: str,
    amount_in: Decimal,
    bin_step: int = 20,
    slippage_bps: int | None = None,
) -> SwapResult

Execute a swap with exact input amount.

Note: This method requires a private key to be configured. For building unsigned transactions, use build_swap_transaction().

参数:

名称 类型 描述 默认
token_in str

Input token symbol or address

必需
token_out str

Output token symbol or address

必需
amount_in Decimal

Exact amount of input token

必需
bin_step int

Bin step for the pair

20
slippage_bps int | None

Slippage tolerance in basis points

None

返回:

类型 描述
SwapResult

SwapResult with execution details

引发:

类型 描述
TraderJoeV2SDKError

If execution fails

get_position

get_position(
    token_x: str,
    token_y: str,
    bin_step: int = 20,
    wallet: str | None = None,
) -> LiquidityPosition | None

Get liquidity position for a wallet in a pool.

参数:

名称 类型 描述 默认
token_x str

Token X symbol or address

必需
token_y str

Token Y symbol or address

必需
bin_step int

Bin step of the pool

20
wallet str | None

Wallet address (default: configured wallet)

None

返回:

类型 描述
LiquidityPosition | None

LiquidityPosition if found, None if no position

build_add_liquidity_transaction

build_add_liquidity_transaction(
    token_x: str,
    token_y: str,
    amount_x: Decimal,
    amount_y: Decimal,
    bin_step: int = 20,
    bin_range: int = 10,
    slippage_bps: int | None = None,
    id_slippage: int = 50,
) -> TransactionData

Build an add liquidity transaction.

Creates a uniform distribution across bins around the active bin.

参数:

名称 类型 描述 默认
token_x str

Token X symbol or address

必需
token_y str

Token Y symbol or address

必需
amount_x Decimal

Amount of token X to add

必需
amount_y Decimal

Amount of token Y to add

必需
bin_step int

Bin step of the pool

20
bin_range int

Number of bins on each side of active bin

10
slippage_bps int | None

Slippage tolerance in basis points

None
id_slippage int

Allowed deviation in active bin ID between pool query and TX execution. Default 50 (was 5, increased to handle Avalanche's high throughput where bins shift between simulation and execution). VIB-2579.

50

返回:

类型 描述
TransactionData

TransactionData ready for signing and execution

build_remove_liquidity_transaction

build_remove_liquidity_transaction(
    token_x: str,
    token_y: str,
    bin_step: int = 20,
    slippage_bps: int | None = None,
    position: LiquidityPosition | None = None,
    amount_x_min: int | None = None,
    amount_y_min: int | None = None,
) -> TransactionData | None

Build a remove liquidity transaction for all positions.

参数:

名称 类型 描述 默认
token_x str

Token X symbol or address

必需
token_y str

Token Y symbol or address

必需
bin_step int

Bin step of the pool

20
slippage_bps int | None

Slippage tolerance in basis points

None
position LiquidityPosition | None

Optional pre-fetched position. If provided, skips the get_position() call (avoids redundant RPC round trips when the caller already holds the position data).

None
amount_x_min int | None

Optional explicit minimum output for token X.

None
amount_y_min int | None

Optional explicit minimum output for token Y.

None

返回:

类型 描述
TransactionData | None

TransactionData if position exists, None otherwise

get_pending_fees

get_pending_fees(
    token_x: str,
    token_y: str,
    bin_step: int = 20,
    wallet: str | None = None,
) -> CollectFeesResult | None

Query pending fees for an LP position.

参数:

名称 类型 描述 默认
token_x str

Token X symbol or address

必需
token_y str

Token Y symbol or address

必需
bin_step int

Bin step of the pool

20
wallet str | None

Wallet address (default: configured wallet)

None

返回:

类型 描述
CollectFeesResult | None

CollectFeesResult with pending fee info, or None if no position

build_collect_fees_transaction

build_collect_fees_transaction(
    token_x: str, token_y: str, bin_step: int = 20
) -> TransactionData | None

Build a transaction to collect fees from an LP position without closing it.

Calls LBPair.collectFees(account, binIds) which harvests accumulated fees while keeping the liquidity position intact.

参数:

名称 类型 描述 默认
token_x str

Token X symbol or address

必需
token_y str

Token Y symbol or address

必需
bin_step int

Bin step of the pool

20

返回:

类型 描述
TransactionData | None

TransactionData if position exists, None otherwise

TraderJoeV2Config dataclass

TraderJoeV2Config(
    chain: str,
    wallet_address: str,
    rpc_url: str | None = None,
    private_key: str | None = None,
    default_slippage_bps: int = 50,
    default_deadline_seconds: int = 300,
    gateway_client: GatewayClient | None = None,
)

Configuration for TraderJoe V2 adapter.

参数:

名称 类型 描述 默认
chain str

Chain name (must be "avalanche")

必需
wallet_address str

Address of the wallet executing transactions

必需
rpc_url str | None

RPC endpoint URL

None
private_key str | None

Private key for signing (optional, for non-simulation)

None
default_slippage_bps int

Default slippage in basis points (default: 50 = 0.5%)

50
default_deadline_seconds int

Default transaction deadline (default: 300 = 5 min)

300

TransactionData dataclass

TransactionData(
    to: str,
    data: str,
    value: int,
    gas: int,
    chain_id: int = 43114,
)

Transaction data ready for execution.

属性:

名称 类型 描述
to str

Target contract address

data str

Encoded calldata

value int

ETH/AVAX value to send

gas int

Gas limit

chain_id int

Chain ID

TraderJoeV2Compiler

Bases: BaseProtocolCompiler[BaseCompilerContext]

Compiler for TraderJoe V2 Liquidity Book intents.

LiquidityEventData dataclass

LiquidityEventData(
    pool_address: str,
    sender: str,
    to: str,
    bin_ids: list[int],
    amounts_x: list[int] = list(),
    amounts_y: list[int] = list(),
    total_amount_x: int = 0,
    total_amount_y: int = 0,
)

Parsed data from add/remove liquidity events.

ParsedLiquidityResult dataclass

ParsedLiquidityResult(
    success: bool,
    is_add: bool = True,
    pool_address: str | None = None,
    bin_ids: list[int] = list(),
    amount_x: int = 0,
    amount_y: int = 0,
    gas_used: int | None = None,
    block_number: int | None = None,
)

Result of parsing a liquidity transaction.

ParsedSwapResult dataclass

ParsedSwapResult(
    success: bool,
    token_in: str | None = None,
    token_out: str | None = None,
    amount_in: int | None = None,
    amount_out: int | None = None,
    price: Decimal | None = None,
    gas_used: int | None = None,
    block_number: int | None = None,
    timestamp: datetime | None = None,
)

Result of parsing a swap transaction.

ParseResult dataclass

ParseResult(
    success: bool,
    transaction_hash: str,
    block_number: int,
    gas_used: int,
    events: list[TraderJoeV2Event] = list(),
    swap_result: ParsedSwapResult | None = None,
    liquidity_result: ParsedLiquidityResult | None = None,
    error: str | None = None,
)

Result of parsing a transaction receipt.

SwapEventData dataclass

SwapEventData(
    token_in: str,
    token_out: str,
    amount_in: int,
    amount_out: int,
    sender: str,
    recipient: str,
)

Parsed data from a swap (Transfer events).

TraderJoeV2Event dataclass

TraderJoeV2Event(
    event_type: TraderJoeV2EventType,
    event_name: str,
    log_index: int,
    transaction_hash: str,
    block_number: int,
    contract_address: str,
    data: dict[str, Any],
    raw_topics: list[str] = list(),
    raw_data: str = "",
    timestamp: datetime | None = None,
)

Parsed TraderJoe V2 event.

TraderJoeV2EventType

Bases: Enum

TraderJoe V2 event types.

TraderJoeV2ReceiptParser

TraderJoeV2ReceiptParser(
    chain: str | None = None, **kwargs: Any
)

Parser for TraderJoe V2 transaction receipts.

Refactored to use base infrastructure utilities for hex decoding and event registry management. Now properly parses dynamic arrays in DepositedToBins and WithdrawnFromBins events.

Initialize the parser.

参数:

名称 类型 描述 默认
chain str | None

Chain name for token decimal resolution (e.g. "avalanche", "bsc"). When provided, extract_swap_amounts() uses actual token decimals instead of assuming 18 for all tokens.

None
**kwargs Any

Additional arguments (ignored for compatibility)

{}

parse_receipt

parse_receipt(receipt: dict[str, Any]) -> ParseResult

Parse a transaction receipt.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Web3 transaction receipt dict

必需

返回:

类型 描述
ParseResult

ParseResult with extracted data

parse_swap_events

parse_swap_events(
    receipt: dict[str, Any],
) -> list[SwapEventData]

Parse swap events from a receipt.

Convenient method to extract all swap-related data.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Web3 transaction receipt dict

必需

返回:

类型 描述
list[SwapEventData]

List of SwapEventData objects

extract_swap_amounts

extract_swap_amounts(
    receipt: dict[str, Any],
    *,
    expected_out: Decimal | None = None,
) -> SwapAmounts | None

Extract swap amounts from a transaction receipt.

Uses actual token decimals when chain is known (passed to init). Falls back to 18 decimals when chain is unavailable.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

必需
expected_out Decimal | None

VIB-3203 Phase B — pre-slippage-discount quote in human (Decimal) units, sourced from ActionBundle.metadata["expected_output_human"] by the ResultEnricher. When provided and positive, realized slippage_bps is computed. When absent, slippage_bps stays None.

None

返回:

类型 描述
SwapAmounts | None

SwapAmounts dataclass if swap event found, None otherwise

extract_bin_ids

extract_bin_ids(
    receipt: dict[str, Any],
) -> list[int] | None

Extract bin IDs from LP transaction receipt.

TraderJoe V2 uses bins for liquidity. This extracts the bin IDs from DepositedToBins or WithdrawnFromBins events.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

必需

返回:

类型 描述
list[int] | None

List of bin IDs if found, None otherwise

extract_liquidity

extract_liquidity(receipt: dict[str, Any]) -> int | None

Extract total liquidity from LP transaction receipt.

Note: TraderJoe V2 uses ERC-1155 tokens for LP positions (not ERC-20). Liquidity amounts are encoded in DepositedToBins/WithdrawnFromBins events as bytes32 arrays requiring complex decoding. This method returns None as the exact liquidity amount extraction is not yet implemented.

For LP operation detection, use parse_receipt().liquidity_result instead.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

必需

返回:

类型 描述
int | None

None (liquidity amount extraction not implemented for TraderJoe V2)

extract_collected_fees

extract_collected_fees(
    receipt: dict[str, Any],
) -> ParsedFeeCollectionResult | None

Extract collected fees data from a fee collection transaction receipt.

Looks for ClaimedFees events and Transfer events to determine fee amounts. Returns None if ClaimedFees is not found (older LBPair versions without this event).

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

必需

返回:

类型 描述
ParsedFeeCollectionResult | None

ParsedFeeCollectionResult if fee collection found, None otherwise

extract_protocol_fees

extract_protocol_fees(
    receipt: dict[str, Any],
) -> ProtocolFees

VIB-3495: TraderJoe V2 LP protocol fee coverage audit.

TraderJoe V2 (Liquidity Book) charges a swap fee on trades that traverse active bins; this fee accrues to LPs and is claimable via collectFees() / ClaimedFees events. The ClaimedFees event carries bin-level amounts as packed bytes32[] and ERC-20 Transfer events carry the actual token amounts — but there is no on-chain protocol-level fee (the fee IS the LP reward). Since there is no on-chain USD price for the fee amounts available at the receipt layer, the USD amount is unavailable.

Returns a ProtocolFees with unavailable_reason so downstream attribution records "known-unknown" rather than silently omitting the field (which would set protocol_fees_usd="" and produce fee_pnl=None in PnL attribution — the correct outcome, but now explicitly flagged by the parser rather than by parser absence).

extract_fees0

extract_fees0(receipt: dict[str, Any]) -> int | None

Extract fee amount for token X from fee collection receipt.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict

必需

返回:

类型 描述
int | None

Fee amount in wei for token X, or None

extract_fees1

extract_fees1(receipt: dict[str, Any]) -> int | None

Extract fee amount for token Y from fee collection receipt.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict

必需

返回:

类型 描述
int | None

Fee amount in wei for token Y, or None

extract_lp_open_data

extract_lp_open_data(
    receipt: dict[str, Any],
) -> LPOpenData | None

Extract LP open data from a TraderJoe V2 (Liquidity Book) receipt.

VIB-4634 — chain-data-first pool-address stamping. The Liquidity Book DepositedToBins(address sender, address to, uint256[] ids, bytes32[] amounts) event is emitted BY the LBPair contract itself, so event.contract_address IS the canonical LBPair (pool) address — no factory lookup or extra RPC needed. Stamping it on LPOpenData.pool_address lets the LP accounting handler's resolver accept-branch (^0x[0-9a-f]{40}$) book the LP_OPEN event, instead of dropping it because the position-key tail (tokenX/tokenY/<binStep>) is rejected by _clean_pool_address_candidate as a Uniswap-V3 fee-tier descriptor. Mirrors the Uniswap V3 Mint/IncreaseLiquidity pool_address path (VIB-3893).

Bin-model directional null-contract (Empty ≠ Zero ≠ None, blueprint 27 §10.10): the Liquidity Book has NO NFT token id and NO tick bracket, so position_id is 0 (the fungible-LP "no discriminator" sentinel the accounting handler maps to None) and tick_lower / tick_upper / liquidity / current_tick stay None — never fabricated. amount0 / amount1 are the raw token-X / token-Y deposit amounts decoded from the ERC-20 Transfer legs (wallet → LBPair); the handler scales them by token decimals. Returns None when no DepositedToBins event is in the receipt (e.g. a failed mid-bundle open).

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict with 'logs' field.

必需

返回:

类型 描述
LPOpenData | None

LPOpenData if a DepositedToBins event is present,

LPOpenData | None

None otherwise.

extract_lp_close_data

extract_lp_close_data(
    receipt: dict[str, Any],
) -> LPCloseData | None

Extract LP close data from transaction receipt.

Looks for WithdrawnFromBins events and Transfer events.

VIB-4634 — stamp the canonical LBPair (pool) address on the close leg. The WithdrawnFromBins event is emitted BY the LBPair, so event.contract_address IS the pool address (chain-truth, no factory lookup). Mirrors the Uniswap V3 Burn pool_address path (VIB-3940). Without it the LP accounting handler drops every TraderJoe V2 LP_CLOSE / LP_COLLECT_FEES because the position-key tail tokenX/tokenY/<binStep> is rejected as a V3 fee-tier descriptor.

参数:

名称 类型 描述 默认
receipt dict[str, Any]

Transaction receipt dict with 'logs' field

必需

返回:

类型 描述
LPCloseData | None

LPCloseData dataclass if withdrawal found, None otherwise

extract_primitive_money_legs

extract_primitive_money_legs(
    receipt: dict[str, Any],
) -> PrimitiveMoneyLegs | None

VIB-5221 (US-011) — declare the LP_CLOSE money legs as a typed PrimitiveMoneyLegs the ledger dispatcher consumes directly.

Inverts the legacy control flow (blueprint 27 §6.6, 05 §7): instead of the ledger reverse-engineering an LP_CLOSE's token0 / token1 from the intent's pool descriptor (the #2894 / VIB-5195 _pair_tokens_from_intent threading), the connector DECLARES the two proceeds tokens it actually withdrew on-chain. Legs are built FROM the LBPair → wallet WithdrawnFromBins Transfer legs (chain truth), so they are independent of the intent AND of the position_id — a fungible-LP close under a synthetic id (traderjoe_*_lp_0) declares the same legs as an NFT close, which is exactly the case #2894 had to special-case.

Two OUTPUT legs in tokenX-then-tokenY (amount0 / amount1) emission order — the dispatcher (_extract_from_declared_legs) projects leg0 → token_in / amount_in and leg1 → token_out / amount_out, lane-symmetric with the legacy _extract_from_lp_close. Amounts are human-unit MeasuredMoney carrying Empty ≠ Zero (§10.10); see _build_close_output_leg.

Returns None (→ benign ExtractMissing) when the receipt is not a principal-withdrawal close (an add, a fees-only ClaimedFees collect, or a degenerate zero-amount withdrawal), so the dispatcher falls through to the legacy LP_CLOSE path unchanged. Never raises: any failure degrades to None rather than halting the live accounting writer.

TransferEventData dataclass

TransferEventData(
    token: str,
    from_address: str,
    to_address: str,
    amount: int,
)

Parsed data from Transfer event.

InvalidBinStepError

InvalidBinStepError(bin_step: int)

Bases: TraderJoeV2SDKError

Invalid bin step provided.

PoolInfo dataclass

PoolInfo(
    address: str,
    token_x: str,
    token_y: str,
    bin_step: int,
    active_id: int,
    reserve_x: int,
    reserve_y: int,
)

Information about a TraderJoe V2 LBPair pool.

PoolNotFoundError

PoolNotFoundError(
    token_x: str, token_y: str, bin_step: int
)

Bases: TraderJoeV2SDKError

Pool does not exist.

TraderJoeV2SDK

TraderJoeV2SDK(
    chain: str,
    rpc_url: str | None = None,
    wallet_address: str | None = None,
    gateway_client: GatewayClient | None = None,
)

TraderJoe Liquidity Book V2 SDK.

Provides methods for: - Token swaps (exact input) - Add/remove liquidity - Pool queries - Bin math utilities

参数:

名称 类型 描述 默认
chain str

Chain name (e.g., "avalanche")

必需
rpc_url str | None

RPC endpoint URL

None
wallet_address str | None

Optional wallet address for transactions

None
Example

sdk = TraderJoeV2SDK( chain="avalanche", rpc_url="https://api.avax.network/ext/bc/C/rpc", )

Get pool info

pool = sdk.get_pool_address(wavax, usdc, bin_step=20)

Build swap transaction

tx, gas = sdk.build_swap_exact_tokens_for_tokens( amount_in=10**18, amount_out_min=0, path=[wavax, usdc], bin_steps=[20], recipient="0x...", )

get_token_contract

get_token_contract(token_address: str) -> Contract

Get or create a token contract instance.

get_balance

get_balance(token_address: str, account: str) -> int

Get the token balance of an account.

get_allowance

get_allowance(
    token_address: str, owner: str, spender: str
) -> int

Get the allowance of a spender for a token owner.

get_pool_address

get_pool_address(
    token_x: str, token_y: str, bin_step: int
) -> str

Get the LBPair (pool) address for a given token pair and binStep.

Results are cached in-process: the LBFactory pair address is immutable and does not change after pool creation.

参数:

名称 类型 描述 默认
token_x str

Address of token X

必需
token_y str

Address of token Y

必需
bin_step int

Bin step of the pair (e.g., 20 for 0.2%)

必需

返回:

类型 描述
str

Address of the LBPair contract

引发:

类型 描述
PoolNotFoundError

If no pool exists for the pair/binStep

get_lb_pair_information

get_lb_pair_information(
    token_x: str, token_y: str, bin_step: int
) -> LBPairInformation

Resolve the full LBPair information for a pair + binStep.

Unlike :meth:get_pool_address (which discards everything but the address), this surfaces the ignoredForRouting flag so callers can skip deprecated pools the router refuses to route through (VIB-3100).

参数:

名称 类型 描述 默认
token_x str

Address of token X

必需
token_y str

Address of token Y

必需
bin_step int

Bin step of the pair (e.g., 20 for 0.2%)

必需

返回:

名称 类型 描述
Decoded LBPairInformation

class:LBPairInformation.

引发:

类型 描述
PoolNotFoundError

Only for a GENUINE pool-absence signal — the factory returns the zero address for the pair/binStep.

TraderJoeV2SDKError

For any other failure (RPC/network/ABI error). Callers that skip absent bin steps (autodetect) MUST NOT swallow this — a transient RPC error must fail loud, never be masked as "pool not found", or autodetect could silently pick a shallower wrong pool because a deeper candidate errored (VIB-3100 Gemini HIGH).

get_pair_contract

get_pair_contract(pool_address: str) -> Contract

Get or create a pair contract instance.

get_pool_info

get_pool_info(pool_address: str) -> PoolInfo

Get information about a pool.

get_pool_spot_rate

get_pool_spot_rate(pool_address: str) -> float

Get the current spot price from a TraderJoe V2 LBPair pool.

Price is calculated from the active bin ID using the formula: price = (1 + binStep/10000)^(activeId - 8388608) * 10^(decimalsX - decimalsY)

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract

必需

返回:

类型 描述
float

Current spot price (tokenY per tokenX)

bin_id_to_price staticmethod

bin_id_to_price(
    bin_id: int,
    bin_step: int,
    decimals_x: int = 18,
    decimals_y: int = 18,
) -> float

Convert a bin ID to price using TraderJoe V2 formula.

Formula: price = (1 + binStep/10000)^(binId - 8388608) * 10^(decimalsX - decimalsY)

参数:

名称 类型 描述 默认
bin_id int

The bin ID

必需
bin_step int

The bin step for the pair

必需
decimals_x int

Decimals of tokenX (default 18)

18
decimals_y int

Decimals of tokenY (default 18)

18

返回:

类型 描述
float

Price (tokenY per tokenX), adjusted for decimals

price_to_bin_id staticmethod

price_to_bin_id(
    price: float,
    bin_step: int,
    decimals_x: int = 18,
    decimals_y: int = 18,
) -> int

Convert a price to the nearest bin ID using TraderJoe V2 formula.

Inverse formula: binId = (log(price) - (decimalsX - decimalsY) * log(10)) / log(1 + binStep/10000) + 8388608

参数:

名称 类型 描述 默认
price float

Target price (tokenY per tokenX)

必需
bin_step int

The bin step for the pair

必需
decimals_x int

Decimals of tokenX (default 18)

18
decimals_y int

Decimals of tokenY (default 18)

18

返回:

类型 描述
int

Nearest bin ID

build_approve_transaction

build_approve_transaction(
    token_address: str,
    spender_address: str,
    amount: int,
    from_address: str,
) -> tuple[dict[str, Any], int]

Build an approve transaction for a token.

参数:

名称 类型 描述 默认
token_address str

Address of the token to approve

必需
spender_address str

Address of the spender (usually router)

必需
amount int

Amount to approve (in wei)

必需
from_address str

Address of the token owner

必需

返回:

类型 描述
tuple[dict[str, Any], int]

Tuple of (transaction dict, estimated gas)

build_approve_for_all_transaction

build_approve_for_all_transaction(
    pool_address: str,
    spender_address: str,
    from_address: str,
    approved: bool = True,
) -> tuple[dict[str, Any], int]

Build approveForAll transaction for LB token (ERC1155-like).

LB tokens require approveForAll before the router can remove liquidity.

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract

必需
spender_address str

Address of the spender (usually router)

必需
from_address str

Address of the token owner

必需
approved bool

Whether to approve or revoke

True

返回:

类型 描述
tuple[dict[str, Any], int]

Tuple of (transaction dict, estimated gas)

build_swap_exact_tokens_for_tokens

build_swap_exact_tokens_for_tokens(
    amount_in: int,
    amount_out_min: int,
    path: list[str],
    bin_steps: list[int],
    recipient: str,
    deadline: int | None = None,
) -> tuple[dict[str, Any], int]

Build transaction for swapping exact tokens for tokens.

参数:

名称 类型 描述 默认
amount_in int

Amount of input token (in wei)

必需
amount_out_min int

Minimum amount of output token (in wei)

必需
path list[str]

List of token addresses [tokenIn, tokenOut] or multi-hop

必需
bin_steps list[int]

List of binSteps for each pair in the path

必需
recipient str

Address to receive output tokens

必需
deadline int | None

Transaction deadline (default: current time + 100 days)

None

返回:

类型 描述
tuple[dict[str, Any], int]

Tuple of (transaction dict, estimated gas)

build_add_liquidity

build_add_liquidity(
    token_x: str,
    token_y: str,
    bin_step: int,
    amount_x: int,
    amount_y: int,
    amount_x_min: int,
    amount_y_min: int,
    active_id_desired: int,
    id_slippage: int,
    delta_ids: list[int],
    distribution_x: list[int],
    distribution_y: list[int],
    to: str,
    refund_to: str,
    deadline: int | None = None,
) -> tuple[dict[str, Any], int]

Build transaction for adding liquidity to a TraderJoe V2 pair.

参数:

名称 类型 描述 默认
token_x str

Address of token X

必需
token_y str

Address of token Y

必需
bin_step int

Bin step of the pair

必需
amount_x int

Amount of token X to add

必需
amount_y int

Amount of token Y to add

必需
amount_x_min int

Minimum amount of token X (slippage protection)

必需
amount_y_min int

Minimum amount of token Y (slippage protection)

必需
active_id_desired int

Desired active bin ID

必需
id_slippage int

Allowed slippage on active bin ID

必需
delta_ids list[int]

Delta IDs for liquidity distribution (relative to active)

必需
distribution_x list[int]

Distribution of token X across bins (sum to 10^18)

必需
distribution_y list[int]

Distribution of token Y across bins (sum to 10^18)

必需
to str

Address to mint LB tokens to

必需
refund_to str

Address to refund excess tokens to

必需
deadline int | None

Transaction deadline

None

返回:

类型 描述
tuple[dict[str, Any], int]

Tuple of (transaction dict, estimated gas)

build_remove_liquidity

build_remove_liquidity(
    token_x: str,
    token_y: str,
    bin_step: int,
    amount_x_min: int,
    amount_y_min: int,
    ids: list[int],
    amounts: list[int],
    to: str,
    deadline: int | None = None,
) -> tuple[dict[str, Any], int]

Build transaction for removing liquidity from a TraderJoe V2 pair.

参数:

名称 类型 描述 默认
token_x str

Address of token X

必需
token_y str

Address of token Y

必需
bin_step int

Bin step of the pair

必需
amount_x_min int

Minimum amount of token X to receive

必需
amount_y_min int

Minimum amount of token Y to receive

必需
ids list[int]

Array of bin IDs to remove liquidity from

必需
amounts list[int]

Array of amounts of LB tokens to burn for each bin

必需
to str

Address to receive tokens

必需
deadline int | None

Transaction deadline

None

返回:

类型 描述
tuple[dict[str, Any], int]

Tuple of (transaction dict, estimated gas)

build_collect_fees

build_collect_fees(
    pool_address: str, account: str, ids: list[int]
) -> tuple[dict[str, Any], int]

Build transaction for collecting accumulated fees from an LP position.

Calls LBPair.collectFees(account, ids) which collects fees without removing any liquidity. This is a V2.1 feature of TraderJoe's Liquidity Book.

The returned bytes32[] encodes fee amounts where each bytes32 has amountX in the upper 128 bits and amountY in the lower 128 bits.

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract

必需
account str

Address of the account to collect fees for

必需
ids list[int]

Array of bin IDs to collect fees from

必需

返回:

类型 描述
tuple[dict[str, Any], int]

Tuple of (transaction dict, estimated gas)

引发:

类型 描述
TraderJoeV2SDKError

If no bin IDs provided

get_pending_fees

get_pending_fees(
    pool_address: str, account: str, ids: list[int]
) -> tuple[int, int]

Query pending (uncollected) fees for a position.

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract

必需
account str

Address of the account to query

必需
ids list[int]

Array of bin IDs to query fees for

必需

返回:

类型 描述
tuple[int, int]

Tuple of (total_fees_x, total_fees_y) in wei

get_position_balances

get_position_balances(
    pool_address: str,
    wallet_address: str,
    bin_range: int = 50,
) -> dict[int, int]

Get LB token balances for a wallet across bins.

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract

必需
wallet_address str

Address to query balances for

必需
bin_range int

Number of bins to check on each side of active bin

50

返回:

类型 描述
dict[int, int]

Dict mapping bin ID to balance

get_position_balances_for_ids

get_position_balances_for_ids(
    pool_address: str,
    wallet_address: str,
    bin_ids: list[int],
) -> dict[int, int]

Get LB token balances for a wallet in specific bins.

Use this when the caller already knows which bins matter and wants to avoid the broader active-bin scan performed by get_position_balances().

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract

必需
wallet_address str

Address to query balances for

必需
bin_ids list[int]

Exact bin IDs to query

必需

返回:

类型 描述
dict[int, int]

Dict mapping bin ID to balance for bins with non-zero balance

get_total_position_value

get_total_position_value(
    pool_address: str,
    wallet_address: str,
    precomputed_balances: dict[int, int] | None = None,
    *,
    strict: bool = False,
    sanity_floor: float = 0.9,
) -> tuple[int, int]

Get total token amounts for a wallet's position in a pool.

Computes per-bin share of LBPair reserves: for each bin where the wallet holds LB tokens, reads the bin's reserves and total supply and accumulates the wallet's share. Returns (total_x, total_y) in raw units.

Failure modes & strict parameter: VIB-3757 investigation discovered that the historical "best-effort" behaviour (silently skipping bins on revert) was masking a real bug: the LBPair ABI declared getBin(uint256) while the deployed contract is getBin(uint24), so the function selector was wrong and EVERY call reverted. The function returned (0, 0) for every position, and any caller deriving slippage minimums from this got zero protection.

With the ABI fixed to ``uint24``, well-behaved RPCs should not
revert — this is the strict path. ``strict=True`` raises on the
first per-bin read error so a caller deriving money-critical
values (e.g. slippage minimums) fails loudly instead of silently
shipping a position close with no slippage protection.

``strict=False`` (default for backward compatibility) keeps the
tolerant per-bin behaviour but applies a sanity floor: if more
than ``(1 - sanity_floor)`` of the queried bins fail, the
function raises rather than returning a misleading partial
valuation. ``sanity_floor=0.9`` means at least 90% of bins must
succeed; below that we treat the result as untrustworthy.

**Practical effect of the 0.9 default on small positions**:
because the threshold is a ratio, small-N positions effectively
behave like ``strict=True`` for any per-bin failure:

    | bins | success ratio after 1 failure | passes 0.9 floor? |
    | ---- | ----------------------------- | ----------------- |
    |   5  | 4/5 = 80%                     | NO  -> raises     |
    |   9  | 8/9 = 89%                     | NO  -> raises     |
    |  10  | 9/10 = 90%                    | YES -> warns      |
    |  21  | 20/21 = 95%                   | YES -> warns      |

Real TJ V2 LP positions are typically 5-21 bins, so callers
should expect any single per-bin RPC blip on a sub-10-bin
position to surface as a ``RuntimeError`` rather than a
silently degraded valuation. With the ABI selector now correct,
well-behaved RPCs do not revert here, so this is rare in
practice — but the failure mode IS now loud.

参数:

名称 类型 描述 默认
pool_address str

Address of the LBPair contract.

必需
wallet_address str

Address to query.

必需
precomputed_balances dict[int, int] | None

Optional pre-fetched bin balances to avoid a redundant get_position_balances() call (pass the result from a prior call).

None
strict bool

When True, raise on the first per-bin read error. When False (default), tolerate per-bin reverts up to the sanity_floor threshold.

False
sanity_floor float

Minimum fraction of bins that must succeed when strict=False (default 0.9). Below this threshold the method raises RuntimeError rather than returning a misleading partial valuation. Set to 0 to restore the original silent-degradation behaviour (NOT recommended for money-critical callers).

0.9

返回:

类型 描述
int

Tuple of (amount_x, amount_y) the wallet would receive if

int

removing all liquidity.

引发:

类型 描述
RuntimeError

When strict=True and any per-bin call reverts, or when strict=False and the success ratio falls below sanity_floor.

TraderJoeV2SDKError

Bases: Exception

Base exception for TraderJoe V2 SDK errors.

SDKSwapQuote dataclass

SDKSwapQuote(
    amount_in: int,
    amount_out: int,
    path: list[str],
    bin_steps: list[int],
    price_impact: Decimal,
    fee: int,
)

Quote for a swap operation.

__getattr__

__getattr__(name: str) -> Any

PEP 562 lazy attribute access.