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