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.
Execute Swaps
This guide shows how to execute swaps using:
singleSwap(one pool)multiSwap(multiple pools)
It assumes:
- You already understand swap semantics.
- You are interacting with pools that already exist.
- The executor (
msg.sender) is directly supplying input tokens. - No custom transfer handler is used (
transferData = "0x").
For deeper semantics, see:
- Protocol Fundamentals → Swaps
- Fees & Economics
- Hooks
Entry Points
singleSwap
function singleSwap(
SwapOrder calldata swapOrder,
bytes32 poolId,
BPSFeeWithRecipient calldata exchangeFee,
FlatFeeWithRecipient calldata feeOnTop,
SwapHooksExtraData calldata swapHooksExtraData,
bytes calldata transferData
) external payable returns (uint256 amountIn, uint256 amountOut);
multiSwap
function multiSwap(
SwapOrder calldata swapOrder,
bytes32[] calldata poolIds,
BPSFeeWithRecipient calldata exchangeFee,
FlatFeeWithRecipient calldata feeOnTop,
SwapHooksExtraData[] calldata swapHooksExtraDatas,
bytes calldata transferData
) external payable returns (uint256 amountIn, uint256 amountOut);
Return values:
amountIn— total input collected (including execution-level fees)amountOut— output delivered toswapOrder.recipient
Constructing SwapOrder
struct SwapOrder {
uint256 deadline;
address recipient;
int256 amountSpecified; // >0 swap-by-input, <0 swap-by-output
uint256 minAmountSpecified; // partial fill tolerance
uint256 limitAmount; // min output (input mode) or max input (output mode)
address tokenIn;
address tokenOut;
}
You are responsible for:
- Setting
deadline - Encoding swap mode via the sign of
amountSpecified - Setting
limitAmountcorrectly for your mode - Setting
minAmountSpecifiedaccording to your partial-fill policy
Execution-Level Fees
Swaps accept two fee structs:
struct BPSFeeWithRecipient {
address recipient;
uint256 BPS;
}
struct FlatFeeWithRecipient {
address recipient;
uint256 amount;
}
Rules:
- If
recipient == address(0)→ fee value must be 0. - BPS bounds depend on swap mode (see Fees & Economics).
- Fee-on-top constraints depend on swap mode.
Hook Calldata
struct SwapHooksExtraData {
bytes tokenInHook;
bytes tokenOutHook;
bytes poolHook;
bytes poolType;
}
If no hook requires calldata:
SwapHooksExtraData({
tokenInHook: "",
tokenOutHook: "",
poolHook: "",
poolType: ""
})
For multiSwap, provide one SwapHooksExtraData per hop.
Token Approvals
For direct executor settlement:
msg.sendersuppliestokenIn- LBAMM pulls via
transferFrom - The executor must approve LBAMM beforehand
If using wrapped native input:
msg.valuemay be used- Incorrect or unused native value reverts
- Excess native value is refunded
singleSwap Example (Solidity)
SwapOrder memory order = SwapOrder({
deadline: block.timestamp + 60,
recipient: recipient,
amountSpecified: int256(amountIn), // positive => swap-by-input
minAmountSpecified: amountIn,
limitAmount: minAmountOut,
tokenIn: tokenIn,
tokenOut: tokenOut
});
BPSFeeWithRecipient memory exchangeFee = BPSFeeWithRecipient({
recipient: exchangeFeeRecipient,
BPS: 30
});
FlatFeeWithRecipient memory feeOnTop = FlatFeeWithRecipient({
recipient: executorFeeRecipient,
amount: executorFee
});
SwapHooksExtraData memory hookData = SwapHooksExtraData({
tokenInHook: "",
tokenOutHook: "",
poolHook: "",
poolType: ""
});
(uint256 totalIn, uint256 totalOut) =
amm.singleSwap{ value: nativeAmountIn }(
order,
poolId,
exchangeFee,
feeOnTop,
hookData,
"" // no transfer handler
);
multiSwap Example (Solidity)
SwapHooksExtraData[] memory hookDatas = new SwapHooksExtraData[](poolIds.length);
for (uint256 i = 0; i < poolIds.length; i++) {
hookDatas[i] = SwapHooksExtraData("", "", "", "");
}
(uint256 totalIn, uint256 totalOut) =
amm.multiSwap{ value: msg.value }(
order,
poolIds,
exchangeFee,
feeOnTop,
hookDatas,
""
);
Notes:
swapHooksExtraDatas.lengthmust equalpoolIds.length.- A
Swapevent is emitted per hop.
TypeScript Example (singleSwap)
const swapOrder = {
deadline: BigInt(Math.floor(Date.now() / 1000) + 60),
recipient,
amountSpecified: amountIn, // >0 => swap-by-input
minAmountSpecified: amountIn,
limitAmount: minAmountOut,
tokenIn,
tokenOut,
};
const exchangeFee = {
recipient: exchangeFeeRecipient,
BPS: 30n,
};
const feeOnTop = {
recipient: executorFeeRecipient,
amount: executorFee,
};
const hookData = {
tokenInHook: "0x",
tokenOutHook: "0x",
poolHook: "0x",
poolType: "0x",
};
const { request } = await publicClient.simulateContract({
address: ammAddress,
abi: ammAbi,
functionName: "singleSwap",
args: [swapOrder, poolId, exchangeFee, feeOnTop, hookData, "0x"],
value: msgValue,
});
await walletClient.writeContract(request);
Common Integration Errors
Most swap failures come from:
- Expired
deadline - Incorrect
limitAmountfor swap mode - Fee configuration invalid (recipient zero with non-zero value)
- Insufficient allowance or balance
- Route array length mismatch (multiSwap)
- Hook validation reverts
