Aller au contenu

Fluid DEX

Connector for the Fluid DEX (swap) and fToken (ERC-4626 lending) surfaces. The vault borrow surface (NFT-CDP, protocol="fluid_vault") is documented under Fluid Vault.

almanak.connectors.fluid

Fluid DEX Connector — swap surface (Phase 1, VIB-5029).

Provides Fluid DEX exact-input swaps on arbitrum, base, ethereum, and polygon. Fluid is routerless: each pool is a per-pair contract; pool discovery and quoting go through the DexReservesResolver (quotes match on-chain execution to the wei — Phase-0 validation, VIB-5028).

Out of scope here (later phases): fToken lending SUPPLY/WITHDRAW (VIB-5030), vault BORROW/REPAY (VIB-5031), and LP via SmartLending / smart vaults (VIB-5032 — direct pool LP is whitelist-gated on-chain).

Key contracts (identical addresses on all supported chains): - DexFactory: 0x91716C4EDA1Fb55e84Bf8b4c7085f84285c19085 - DexReservesResolver: 0x05Bd8269A20C472b148246De20E6852091BF16Ff

Example

from almanak.connectors.fluid import FluidAdapter, FluidConfig

config = FluidConfig( chain="arbitrum", wallet_address="0x...", rpc_url="https://arb-mainnet.g.alchemy.com/v2/...", ) adapter = FluidAdapter(config)

FluidAdapter

FluidAdapter(
    config: FluidConfig,
    token_resolver: TokenResolver | None = None,
)

High-level adapter for Fluid DEX swap operations.

参数:

名称 类型 描述 默认
config FluidConfig

FluidConfig with chain, wallet, and transport settings

必需
token_resolver TokenResolver | None

Optional TokenResolver for symbol -> address resolution

None

resolve_token_address

resolve_token_address(token: str) -> str

Resolve a token symbol or address to checksummed address.

参数:

名称 类型 描述 默认
token str

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

必需

返回:

类型 描述
str

Checksummed address

get_token_decimals

get_token_decimals(token: str) -> int

Get decimals for a token.

参数:

名称 类型 描述 默认
token str

Token symbol or address

必需

返回:

类型 描述
int

Token decimals (never defaults to 18 — raises if unknown)

find_pool

find_pool(token0: str, token1: str) -> str | None

Find a Fluid DEX pool for a token pair (order-insensitive).

参数:

名称 类型 描述 默认
token0 str

First token symbol or address

必需
token1 str

Second token symbol or address

必需

返回:

类型 描述
str | None

Pool address if found, None otherwise

find_pool_for_pair

find_pool_for_pair(
    token_in: str, token_out: str
) -> tuple[str, bool] | None

Find the pool and swap direction for an exact-input pair.

Returns (pool_address, swap0to1) or None.

get_pool_data

get_pool_data(dex_address: str) -> DexPoolData

Get full pool data (tokens + smart-collateral/debt flags).

get_swap_quote

get_swap_quote(
    token_in: str, token_out: str, amount_in: int
) -> int

Quote an exact-input swap via the DexReservesResolver.

参数:

名称 类型 描述 默认
token_in str

Input token symbol or address

必需
token_out str

Output token symbol or address

必需
amount_in int

Input amount in the token's smallest unit

必需

返回:

类型 描述
int

Expected output amount in the token's smallest unit

引发:

类型 描述
FluidSDKError

If no pool exists or the quote fails

FluidMinAmountError

If the size is limit-gated (retryable)

build_swap_transaction

build_swap_transaction(
    token_in: str,
    token_out: str,
    amount_in: int,
    amount_out_min: int,
    value: int | None = None,
) -> TransactionData

Build a swapIn transaction for an exact-input swap.

参数:

名称 类型 描述 默认
token_in str

Input token symbol or address

必需
token_out str

Output token symbol or address

必需
amount_in int

Input amount in the token's smallest unit

必需
amount_out_min int

Minimum acceptable output (slippage protection)

必需
value int | None

Native value. Defaults to amount_in for native inputs and 0 for ERC-20 inputs; an explicit value that contradicts the input leg raises (the pool enforces msg.value == amountIn for native, 0 for ERC-20 — a mismatched transaction would revert on-chain).

None

返回:

类型 描述
TransactionData

TransactionData targeting the per-pair pool contract

build_approve_tx

build_approve_tx(
    token_address: str,
    spender: str,
    amount: int | None = None,
) -> TransactionData

Build an ERC20 approval transaction.

参数:

名称 类型 描述 默认
token_address str

Token contract address

必需
spender str

Address to approve spending for

必需
amount int | None

Amount to approve (None = max uint256)

None

返回:

类型 描述
TransactionData

TransactionData for the approval

FluidConfig dataclass

FluidConfig(
    chain: str,
    wallet_address: str,
    rpc_url: str | None = None,
    default_slippage_bps: int = 50,
    gateway_client: GatewayClient | None = None,
)

Configuration for Fluid DEX adapter.

参数:

名称 类型 描述 默认
chain str

Chain name (any chain in FLUID_ADDRESSES)

必需
wallet_address str

Address of the wallet executing transactions

必需
rpc_url str | None

DEPRECATED — direct RPC URL. Kept for ad-hoc script usage. Strategies running in isolated containers must use gateway_client.

None
gateway_client GatewayClient | None

Gateway client for routing eth_call through the gateway's RpcService. Preferred over rpc_url.

None
default_slippage_bps int

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

50

FluidCompiler

Bases: BaseProtocolCompiler[SwapCompilerContext]

Fluid DEX swap compiler. SWAP-only, routerless (per-pool targets).

Subclasses BaseProtocolCompiler[SwapCompilerContext] because the swap slippage / price-impact guard reads max_price_impact_pct and using_placeholders — same shape as CamelotCompiler.

compile_swap

compile_swap(
    ctx: SwapCompilerContext, intent: SwapIntent
) -> CompilationResult

Compile a Fluid DEX exact-input swap.

Pipeline: resolve tokens (native legs map to Fluid's 0xEeee… sentinel — Fluid pools pair raw native, not WETH) → resolve the per-pair pool + direction on-chain → quote via the reserves resolver → price-impact guard → approve (ERC-20 input only) + swapIn on the pool.

compile_supply

compile_supply(
    ctx: SwapCompilerContext, intent: Any
) -> CompilationResult

Compile a Fluid fToken supply: approve + ERC-4626 deposit.

compile_withdraw

compile_withdraw(
    ctx: SwapCompilerContext, intent: Any
) -> CompilationResult

Compile a Fluid fToken withdraw.

Exact amounts use ERC-4626 withdraw(assets, ...) behind a maxWithdraw pre-flight; full exits (withdraw_all / amount='all') use redeem(shares, ...) over the exact share balance so rounding can never strand dust shares.

Fluid's withdrawal limits EXPAND OVER TIME: a request beyond the currently-withdrawable amount is a distinct, retryable failure — never a silent clamp, never a compiled-but-doomed transaction.

FluidReceiptParser

FluidReceiptParser(chain: str = 'arbitrum')

Receipt parser for Fluid DEX transactions (swaps and LP operations).

Extracts NFT position IDs and token amounts from LogOperate events. Supports both LP_OPEN (new position) and LP_CLOSE (withdrawal) receipts.

SUPPORTED_EXTRACTIONS declares which ResultEnricher fields this parser supports.

参数:

名称 类型 描述 默认
chain str

Chain name for token resolution (default: "arbitrum")

'arbitrum'

parse_receipt

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

Parse a Fluid DEX transaction receipt.

参数:

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

Transaction receipt dict with 'logs', 'transactionHash', etc.

必需

返回:

类型 描述
FluidParseResult

FluidParseResult with extracted events and data

extract_position_id

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

Extract LP position NFT tokenId from receipt.

Called by ResultEnricher for LP_OPEN intents.

参数:

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

Transaction receipt dict

必需

返回:

类型 描述
int | None

NFT position ID or None if not found

extract_swap_amounts

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

Extract swap amounts from receipt.

Called by ResultEnricher for SWAP intents. Resolves token decimals to produce human-readable decimal amounts (consistent with other parsers).

参数:

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

Transaction receipt dict

必需

返回:

类型 描述
SwapAmounts | None

SwapAmounts with input/output amounts, or None

extract_supply_amount

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

Exact assets supplied, from the fToken's ERC-4626 Deposit event.

Called by ResultEnricher for SUPPLY intents (VIB-5030).

extract_withdraw_amount

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

Exact assets withdrawn, from the fToken's ERC-4626 Withdraw event.

Both withdraw(assets, ...) and full-exit redeem(shares, ...) emit the same event; assets is the underlying amount either way.

extract_lp_close_data

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

Extract LP close data from receipt.

Called by ResultEnricher for LP_CLOSE intents. Returns amounts collected on withdrawal (negative amounts = withdrawn).

参数:

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

Transaction receipt dict

必需

返回:

类型 描述
LPCloseData | None

LPCloseData with collected amounts, or None if not found

extract_liquidity

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

Extract liquidity amount from LP_OPEN receipt.

For Fluid DEX, liquidity is represented by the collateral shares (token0_amt + token1_amt deposited).

参数:

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

Transaction receipt dict

必需

返回:

类型 描述
int | None

Combined deposit amount or None

FluidSDK

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

Low-level Fluid DEX protocol SDK.

Pool enumeration and swap quoting go through the DexReservesResolver (single eth_call each); token-pair / smart-flag verification reads the pool's constantsView() raw words.

参数:

名称 类型 描述 默认
chain str

Chain name (one of FLUID_ADDRESSES)

必需
rpc_url str | None

DEPRECATED — direct RPC URL. Bypasses the gateway and is only used for ad-hoc scripts. Prefer gateway_client for any code path that runs in a strategy container.

None
gateway_client GatewayClient | None

Gateway client used to route all eth_call traffic through the gateway's RpcService. Preferred over rpc_url for production code paths.

None

get_all_dex_addresses

get_all_dex_addresses() -> list[str]

Get all Fluid DEX pool addresses from the resolver.

get_total_dexes

get_total_dexes() -> int

Get the total number of Fluid DEX pools.

get_all_pools

get_all_pools() -> list[DexPoolData]

Enumerate all pools with token pairs in a single eth_call.

Uses DexReservesResolver.getAllPools(). Smart-collateral/debt flags are NOT populated here (use get_dex_data per pool when needed); fee_raw is the resolver-reported raw fee value. The result is cached for the lifetime of this SDK instance.

find_pool_for_pair

find_pool_for_pair(
    token_in: str, token_out: str
) -> tuple[str, bool] | None

Find the Fluid pool for a swap pair and the swap direction.

参数:

名称 类型 描述 默认
token_in str

Input token address (FLUID_NATIVE_TOKEN for native)

必需
token_out str

Output token address

必需

返回:

类型 描述
tuple[str, bool] | None

(pool_address, swap0to1) where swap0to1 is True when

tuple[str, bool] | None

token_in is the pool's token0; None when no pool exists.

find_dex_by_tokens

find_dex_by_tokens(token0: str, token1: str) -> str | None

Find a Fluid DEX pool for a token pair (order-insensitive).

get_dex_data

get_dex_data(dex_address: str) -> DexPoolData

Get pool data by calling constantsView() and readFromStorage().

Uses raw eth_call to avoid ABI decoding issues with the complex DexEntireData struct. constantsView() returns 18 words: - word[9]: token0 address - word[10]: token1 address

readFromStorage(bytes32(0)) returns dexVariables: - bit 1: isSmartCollateralEnabled - bit 2: isSmartDebtEnabled

get_swap_quote

get_swap_quote(
    dex_address: str, swap0to1: bool, amount_in: int
) -> int

Quote an exact-input swap via DexReservesResolver.estimateSwapIn.

This is Fluid's official quote path; Phase-0 validation showed the quote matches real swapIn output to the wei.

参数:

名称 类型 描述 默认
dex_address str

Pool contract address

必需
swap0to1 bool

True to swap token0->token1, False for token1->token0

必需
amount_in int

Input amount in the token's smallest unit

必需

返回:

类型 描述
int

Expected output amount in the token's smallest unit

引发:

类型 描述
FluidMinAmountError

The size is rejected by the pool's time-expanding limits (retryable later / at smaller size).

FluidSDKError

Any other quote failure.

encode_swap_in_calldata

encode_swap_in_calldata(
    swap0to1: bool,
    amount_in: int,
    amount_out_min: int,
    to: str,
) -> str

ABI-encode swapIn calldata (offline — no RPC interaction).

build_swap_tx

build_swap_tx(
    dex_address: str,
    swap0to1: bool,
    amount_in: int,
    amount_out_min: int,
    to: str,
    value: int = 0,
) -> dict[str, Any]

Build a swapIn transaction for a Fluid DEX pool.

参数:

名称 类型 描述 默认
dex_address str

Pool contract address

必需
swap0to1 bool

True to swap token0->token1, False for token1->token0

必需
amount_in int

Input amount in token's smallest unit

必需
amount_out_min int

Minimum acceptable output (slippage protection)

必需
to str

Recipient address

必需
value int

Native token value (must equal amount_in for native-input swaps; 0 for ERC-20 inputs)

0

返回:

类型 描述
dict[str, Any]

Transaction dict with 'to', 'data', 'value', 'gas'

get_all_ftokens

get_all_ftokens() -> list[str]

Enumerate the chain's Fluid fTokens via the LendingResolver.

The result is cached for the lifetime of this SDK instance (fToken listings change rarely; SDK instances are per-compile).

find_ftoken_for_underlying

find_ftoken_for_underlying(underlying: str) -> str | None

Resolve the fToken whose ERC-4626 asset() is underlying.

Fluid lists exactly one fToken per underlying per chain, so the first match is THE market. Returns None when Fluid has no market for the asset on this chain.

get_max_withdraw

get_max_withdraw(ftoken_address: str, owner: str) -> int

ERC-4626 maxWithdraw(owner) — reflects Fluid's time-expanding withdrawal limits, NOT just the owner's balance. The compile-time pre-flight reads this to distinguish "limit-gated, retry later" from a hard failure.

get_max_redeem

get_max_redeem(ftoken_address: str, owner: str) -> int

ERC-4626 maxRedeem(owner) in shares (limit-aware).

get_ftoken_share_balance

get_ftoken_share_balance(
    ftoken_address: str, owner: str
) -> int

fToken share balance of owner (ERC-20 balanceOf on the vault).

convert_to_assets

convert_to_assets(ftoken_address: str, shares: int) -> int

ERC-4626 convertToAssets(shares) — underlying value of shares.

build_deposit_tx

build_deposit_tx(
    ftoken_address: str, assets: int, receiver: str
) -> dict[str, Any]

Build an ERC-4626 deposit(assets, receiver) transaction.

build_withdraw_tx

build_withdraw_tx(
    ftoken_address: str,
    assets: int,
    receiver: str,
    owner: str,
) -> dict[str, Any]

Build an ERC-4626 withdraw(assets, receiver, owner) transaction.

build_redeem_tx

build_redeem_tx(
    ftoken_address: str,
    shares: int,
    receiver: str,
    owner: str,
) -> dict[str, Any]

Build an ERC-4626 redeem(shares, receiver, owner) transaction.

Full exits go through redeem-by-shares (never withdraw-by-assets): burning the exact share balance cannot strand rounding dust.

__getattr__

__getattr__(name: str) -> Any

PEP 562 lazy attribute access.