Skip to main content
Pre-Release Documentation

This describes a pre-release version of LBAMM. Interfaces and behavior may change.

Verify the exact repository commit before building production integrations.

Manage Liquidity

This guide shows how to:

  • Add liquidity to a pool (addLiquidity)
  • Remove liquidity (removeLiquidity)
  • Collect fees (collectFees)

It is written for production integrations that already have:

  • A poolId
  • Token addresses
  • Token approvals in place

This guide intentionally treats poolParams as an opaque ABI-encoded blob. The exact encoding is pool-type-specific.

For simplicity, this guide assumes liquidityHook = address(0) (no position hook). Position hooks are covered separately.


Overview of liquidity entrypoints

LBAMM exposes three liquidity entrypoints:

function addLiquidity(
LiquidityModificationParams calldata liquidityParams,
LiquidityHooksExtraData calldata liquidityHooksExtraData
) external payable returns (uint256 deposit0, uint256 deposit1, uint256 fees0, uint256 fees1);

function removeLiquidity(
LiquidityModificationParams calldata liquidityParams,
LiquidityHooksExtraData calldata liquidityHooksExtraData
) external returns (uint256 withdraw0, uint256 withdraw1, uint256 fees0, uint256 fees1);

function collectFees(
LiquidityCollectFeesParams calldata liquidityParams,
LiquidityHooksExtraData calldata liquidityHooksExtraData
) external returns (uint256 fees0, uint256 fees1);

Liquidity parameter structs

Hook calldata bundle

Liquidity operations accept a single struct containing optional hook calldata:

struct LiquidityHooksExtraData {
bytes token0Hook;
bytes token1Hook;
bytes liquidityHook;
bytes poolHook;
}

In the simplest integration:

  • Provide "0x" for all hook calldata fields.
  • If a token or pool hook requires calldata, supply it in the corresponding field.

Add / Remove liquidity params

struct LiquidityModificationParams {
address liquidityHook;
bytes32 poolId;

uint256 minLiquidityAmount0;
uint256 minLiquidityAmount1;
uint256 maxLiquidityAmount0;
uint256 maxLiquidityAmount1;

uint256 maxHookFee0;
uint256 maxHookFee1;

bytes poolParams;
}

Key fields:

  • liquidityHook: position hook address (use address(0) for none).
  • poolId: pool identifier.
  • min/maxLiquidityAmount0/1: bounds for the operation (deposit/withdraw semantics are pool-type dependent).
  • maxHookFee0/1: maximum hook fees tolerated (if hooks are enabled).
  • poolParams: ABI-encoded pool-type-specific parameters.

The meaning of the min/max liquidity amount fields depends on pool type (and on whether you are depositing or withdrawing). This guide focuses on wiring and call construction; pool-type semantics are documented in the Pool Types section.


Collect fees params

struct LiquidityCollectFeesParams {
address liquidityHook;
bytes32 poolId;

uint256 maxHookFee0;
uint256 maxHookFee1;

bytes poolParams;
}

Step 1: Approvals

For ERC-20 pools, LBAMM core pulls required tokens from the provider (msg.sender) via transferFrom.

That means:

  • The provider must approve LBAMM for token0 and/or token1 before calling addLiquidity.
  • If the provider is a contract (router), the router must hold tokens and provide approvals (and becomes the provider identity).

Native value support (wrapped native pools)

If one of the pool tokens is the Limit Break wrapped native token:

  • msg.value may be used as part of the liquidity deposit.

Rules:

  • If msg.value > 0 and neither token is wrapped native, the call reverts.
  • If msg.value is provided but is insufficient to cover the required native-side deposit, the call reverts.
  • If msg.value is excess, it is refunded when native value is used.

Step 2: Add liquidity (no position hook)

Solidity example

LiquidityModificationParams memory params = LiquidityModificationParams({
liquidityHook: address(0), // no position hook
poolId: poolId,

// Pool-type-dependent bounds (placeholder values)
minLiquidityAmount0: 0,
minLiquidityAmount1: 0,
maxLiquidityAmount0: type(uint256).max,
maxLiquidityAmount1: type(uint256).max,

// Tolerate no hook fees (or set higher if hooks are expected)
maxHookFee0: 0,
maxHookFee1: 0,

// Pool-type-specific encoding (placeholder)
poolParams: abi.encode(/* pool-type params */)
});

LiquidityHooksExtraData memory hookData = LiquidityHooksExtraData({
token0Hook: "",
token1Hook: "",
liquidityHook: "",
poolHook: ""
});

(uint256 deposit0, uint256 deposit1, uint256 fees0, uint256 fees1) =
amm.addLiquidity{ value: nativeDepositAmount }(params, hookData);

TypeScript example (viem-style)

const params = {
liquidityHook: zeroAddress,
poolId,

// Pool-type-dependent bounds (placeholders)
minLiquidityAmount0: 0n,
minLiquidityAmount1: 0n,
maxLiquidityAmount0: (2n ** 256n) - 1n,
maxLiquidityAmount1: (2n ** 256n) - 1n,

maxHookFee0: 0n,
maxHookFee1: 0n,

// Pool-type-specific encoding (placeholder)
poolParams: "0x" as `0x${string}`,
};

const hookData = {
token0Hook: "0x",
token1Hook: "0x",
liquidityHook: "0x",
poolHook: "0x",
};

const { request } = await publicClient.simulateContract({
address: ammAddress,
abi: ammAbi,
functionName: "addLiquidity",
args: [params, hookData],
value: msgValue, // 0n unless wrapped native is involved
});

const hash = await walletClient.writeContract(request);

Step 3: Remove liquidity (no position hook)

Removing liquidity uses the same LiquidityModificationParams struct.

Solidity example

LiquidityModificationParams memory params = LiquidityModificationParams({
liquidityHook: address(0),
poolId: poolId,

// Pool-type-dependent bounds (placeholder values)
minLiquidityAmount0: 0,
minLiquidityAmount1: 0,
maxLiquidityAmount0: type(uint256).max,
maxLiquidityAmount1: type(uint256).max,

maxHookFee0: 0,
maxHookFee1: 0,

poolParams: abi.encode(/* pool-type params */)
});

LiquidityHooksExtraData memory hookData = LiquidityHooksExtraData({
token0Hook: "",
token1Hook: "",
liquidityHook: "",
poolHook: ""
});

(uint256 withdraw0, uint256 withdraw1, uint256 fees0, uint256 fees1) =
amm.removeLiquidity(params, hookData);

Step 4: Collect fees (no position hook)

Fee collection uses LiquidityCollectFeesParams.

Solidity example

LiquidityCollectFeesParams memory params = LiquidityCollectFeesParams({
liquidityHook: address(0),
poolId: poolId,
maxHookFee0: 0,
maxHookFee1: 0,
poolParams: abi.encode(/* pool-type params */)
});

LiquidityHooksExtraData memory hookData = LiquidityHooksExtraData({
token0Hook: "",
token1Hook: "",
liquidityHook: "",
poolHook: ""
});

(uint256 fees0, uint256 fees1) = amm.collectFees(params, hookData);

Notes on failed token transfers (debt)

Liquidity operations attempt required token transfers as part of execution.

If a token transfer fails, LBAMM may store the amount as debt rather than reverting. This behavior is intended to make integrations more robust to non-standard token behavior.

(Exact debt accounting behavior is covered in the protocol reference sections.)

Limit Break

TwitterLimitBreak.comMedium

© 2026 Limit Break International, Inc. All rights reserved.

Privacy PolicyTerms of ServiceCookie PolicyDo Not Sell My Info