This describes a pre-release version of LBAMM. Interfaces and behavior may change.
Verify the exact repository commit before building production integrations.
Direct Swaps
A direct swap is a taker order in which the taker matches against a maker order represented through a transfer handler with the direct swap executor providing the output tokens for the maker's order and receiving the maker's input tokens in exchange. This makes directSwap the primitive for building fillable order systems such as signed permits or onchain order books.
Function Signature
function directSwap(
SwapOrder calldata swapOrder,
DirectSwapParams calldata directSwapParams,
BPSFeeWithRecipient calldata exchangeFee,
FlatFeeWithRecipient calldata feeOnTop,
SwapHooksExtraData calldata swapHooksExtraData,
bytes calldata transferData
) external payable returns (uint256 amountIn, uint256 amountOut);
SwapOrder
Direct swaps use the same SwapOrder struct as pool swaps.
struct SwapOrder {
uint256 deadline;
address recipient;
int256 amountSpecified; // >0 = swap by input, <0 = swap by output
uint256 minAmountSpecified; // no partial fills in directSwap
uint256 limitAmount;
address tokenIn;
address tokenOut;
}
Swap Mode Convention
amountSpecified > 0→ swap by inputamountSpecified < 0→ swap by output
The sign convention is identical to pool swaps for consistency of intent.
DirectSwapParams
struct DirectSwapParams {
uint256 swapAmount;
uint256 maxAmountOut;
uint256 minAmountIn;
}
These parameters bound execution when hook fees are applied:
swapAmount→ base amount for direct executionmaxAmountOut→ maximum the executor may be required to provideminAmountIn→ minimum the executor must receive
Direct swaps do not partially fill. If bounds are violated, the transaction reverts.
Fee Structs
struct BPSFeeWithRecipient {
uint16 BPS;
address recipient;
}
struct FlatFeeWithRecipient {
uint256 amount;
address recipient;
}
Both exchange fees and flat fees are supported.
SwapHooksExtraData
Only token hook data is supported.
struct SwapHooksExtraData {
bytes tokenInHook;
bytes tokenOutHook;
bytes poolHook; // must be empty
bytes poolType; // must be empty
}
If poolHook or poolType are non-empty, the transaction reverts.
transferData (Transfer Handler Settlement)
directSwap is typically used with a transfer handler.
If transferData.length >= 32:
- First 32 bytes: ABI-encoded
address transferHandler - Remaining bytes: handler-specific
transferExtraData
Conceptually:
transferData =
[32 bytes: abi.encode(transferHandler)]
[N bytes : transferExtraData]
Mental Model
A direct swap is:
- A taker order submitted to LBAMM
- Matched directly against a maker order represented by a transfer handler
Example:
- Maker signs a permit offering Token A for Token B
- Taker calls
directSwap - LBAMM collects Token B from the taker
- PermitTransferHandler validates and consumes the permit, supplying Token A to LBAMM
- LBAMM disburses Token A to the taker and Token B to the maker
This enables offchain order books of signed maker intent.
Solidity Example (Permit-Based Direct Swap)
SwapOrder memory order = SwapOrder({
deadline: block.timestamp + 300,
recipient: msg.sender,
amountSpecified: int256(1e18),
minAmountSpecified: 0,
limitAmount: 0,
tokenIn: address(tokenA),
tokenOut: address(tokenB)
});
DirectSwapParams memory params = DirectSwapParams({
swapAmount: 1e18,
maxAmountOut: 1.02e18,
minAmountIn: 0.98e18
});
// PermitTransferHandler encoding
bytes1 permitType = 0x00; // FILL_OR_KILL_PERMIT
bytes memory permitStruct = abi.encode(/* permit fields */);
bytes memory transferData = abi.encodePacked(
abi.encode(address(PERMIT_TRANSFER_HANDLER)),
permitType,
permitStruct
);
amm.directSwap(
order,
params,
BPSFeeWithRecipient({BPS: 0, recipient: address(0)}),
FlatFeeWithRecipient({amount: 0, recipient: address(0)}),
SwapHooksExtraData("", "", "", ""),
transferData
);
viem Example
import { encodeAbiParameters, concatHex } from 'viem'
const transferData = concatHex([
encodeAbiParameters([{ type: 'address' }], [permitHandler]),
'0x00', // FILL_OR_KILL_PERMIT
permitStructEncoded
])
await walletClient.writeContract({
address: ammAddress,
abi: ammAbi,
functionName: 'directSwap',
args: [
swapOrder,
directSwapParams,
{ BPS: 0, recipient: zeroAddress },
{ amount: 0n, recipient: zeroAddress },
{ tokenInHook: '0x', tokenOutHook: '0x', poolHook: '0x', poolType: '0x' },
transferData,
],
})
