# almm:create-limit-order — Ammora SDK 0.3.8 Check the source for arguments and transaction requirements. [Read in Docs](https://docs.ammora.org/examples?command=almm%3Acreate-limit-order) · [Detailed guide](https://docs.ammora.org/guides/src-almm-readme) · [Local setup](https://docs.ammora.org/guides/example-setup) ## Context and execution GIWA Sepolia 91342. Public SDK 0.3.8, Math 0.3.0. Source revision: `a9b3fd798fa51495e8defec99a25de59e4d70672`. Install the SDK in your app, or prepare the example project using the local setup guide for its npm commands. Review the entry source and guide for required arguments, roles and deployment selection. `AMMORA_SEND=0` does not turn send-only commands into previews. Never put CLI keys in a browser or resend an uncertain transaction. Command: `npm run almm:create-limit-order -- ` (`tsx src/almm/create-limit-order.ts`). Omit `--` and arguments when the source accepts none. ## Entry file: `src/almm/create-limit-order.ts` ```typescript import { tokenAmount } from "../shared/input.js"; /** * Place a resting order on a bin pool at a price you choose. * * npm run almm:create-limit-order -- [binsAway] * * A swap takes whatever the pool offers now. A limit order sits in a single bin and is * filled by other people's swaps as price reaches it, so you name the price instead of * accepting it. Nothing is filled at the moment you place it. * * ── Which side you sell decides which way the order can sit ─────────────────── * A bin above the active one holds base, and a bin below it holds quote. So an * order to sell base has to rest at or above the active bin, and one to sell * quote at or below. The manager rejects the other arrangement outright, since * it would be an order that is already through the money. * * `binsAway` is that distance. This example turns it into the signed offset the * manager wants, since it adds the offset to the active bin as given. Further out * is a better price and a longer wait. * * The bin also has to be free of the token you would be paid in. An order is * liquidity in a single bin, and joining a bin that already holds proceeds would * hand the new order a share of them, so the manager refuses. * * ── The order is a token ────────────────────────────────────────────────────── * Placing one mints an order id to `recipient`, and `almm:close-limit-order` * takes it from there: claiming whatever filled, cancelling whatever did not, and * collecting the fees the resting liquidity earned in the meantime. * ─────────────────────────────────────────────────────────────────────────────── */ import { parseEventLogs } from "viem"; import { ALMMClient, almmLimitOrderManagerAbi, buildCreateALMMLimitOrderRelative, } from "@ammora-protocol/sdk"; import { clientOptions, address, deployment, reader, signer } from "../shared/env.js"; import { amount, approve, asPool, main, preflight, requireContract, send, tokenInfo } from "../shared/run.js"; /** Bins away from the active one. One bin is one bin-step of price. */ const DEFAULT_BINS_AWAY = 2; /** How far the active bin may drift before placing is abandoned. */ const ACTIVE_BIN_SLIPPAGE = 3; main(async () => { const [poolArgument, sideArgument, amountArgument, binsArgument] = process.argv.slice(2); const pool = address("ALMM_POOL", poolArgument); if (sideArgument !== "base" && sideArgument !== "quote") { throw new Error("say which side you are selling: base or quote"); } if (!amountArgument) { throw new Error("usage: npm run almm:create-limit-order -- [binsAway]"); } const sellBase = sideArgument === "base"; const binsAway = Number(binsArgument ?? DEFAULT_BINS_AWAY); if (!Number.isInteger(binsAway) || binsAway < 0) { throw new Error("binsAway must be a whole number of bins"); } const { wallet, account } = signer(); const client = await reader(); const contracts = deployment().contracts.liquidityMarketMaker; await requireContract(client, "pool", pool); await requireContract(client, "limit order manager", contracts.limitOrderManager); const sdk = new ALMMClient(client, pool, contracts.positionManager, contracts.binLens, clientOptions()); const state = await asPool(pool, "a bin pool", () => sdk.getPoolState()); const [base, quote] = await Promise.all([ tokenInfo(client, state.baseToken), tokenInfo(client, state.quoteToken), ]); const input = sellBase ? base : quote; const inputToken = sellBase ? state.baseToken : state.quoteToken; const inputAmount = tokenAmount(amountArgument, input.decimals); // The offset is signed and applied as `activeId + binOffset`, so the sign is what puts // the order on the correct side of the price: base sells rest above, quote sells below. // Passing a distance without the sign puts a quote sell above the price, which the // manager rejects as InvalidOrder because it would already be through the money. const activeId = Number(state.activeId); const binOffset = sellBase ? binsAway : -binsAway; const restingBin = activeId + binOffset; console.log(`pool ${pool}`); console.log(`selling ${amount(inputAmount, input.decimals, input.symbol)}`); console.log(`resting at bin ${restingBin} (active ${activeId}, ${binsAway} away)`); console.log(`aborts if the active bin moves more than ${ACTIVE_BIN_SLIPPAGE} bins`); console.log(""); const transaction = { to: contracts.limitOrderManager, ...buildCreateALMMLimitOrderRelative( pool, binOffset, sellBase, inputAmount, // One bin, so one floor. Zero would let the deposit mint nothing and still succeed; // 1 asks only that the order exists, which is what a resting order needs. 1n, account.address, activeId, ACTIVE_BIN_SLIPPAGE, BigInt(Math.floor(Date.now() / 1000) + 600), ), }; await approve( [{ token: inputToken, spender: contracts.limitOrderManager, amount: inputAmount }], wallet, account, client, ); await preflight(client, account, transaction, almmLimitOrderManagerAbi, "create limit order"); const hash = await send("create limit order", transaction, wallet, account, client); const receipt = await client.getTransactionReceipt({ hash }); const created = parseEventLogs({ abi: almmLimitOrderManagerAbi, eventName: "LimitOrderCreated", logs: receipt.logs, }).find((log) => log.address.toLowerCase() === contracts.limitOrderManager.toLowerCase()); if (!created) throw new Error("limit-order receipt contains no creation event"); console.log(` order id: ${(created.args as { orderId: bigint }).orderId}`); }); ``` ## Supporting files Keep relative paths intact. Local imports are listed recursively; JSON templates are choices to review, not approved inputs. Runtime-selected files and wallet/environment setup still follow the detailed guide. - [src/shared/env.ts](https://docs.ammora.org/examples/source/src/shared/env.ts.txt) - [src/shared/input.ts](https://docs.ammora.org/examples/source/src/shared/input.ts.txt) - [src/shared/retry.ts](https://docs.ammora.org/examples/source/src/shared/retry.ts.txt) - [src/shared/rpc.ts](https://docs.ammora.org/examples/source/src/shared/rpc.ts.txt) - [src/shared/run.ts](https://docs.ammora.org/examples/source/src/shared/run.ts.txt) - [src/almm/rebalance.example.json](https://docs.ammora.org/examples/source/src/almm/rebalance.example.json.txt) - [package.json](https://docs.ammora.org/examples/source/package.json.txt) - [package-lock.json](https://docs.ammora.org/examples/source/package-lock.json.txt) - [tsconfig.json](https://docs.ammora.org/examples/source/tsconfig.json.txt) - [.env.giwa.example](https://docs.ammora.org/examples/source/file.env.giwa.example.txt) - [.nvmrc](https://docs.ammora.org/examples/source/file.nvmrc.txt) ## AI implementation checklist Use the actual SDK exports and parameter types in the linked files. Start with reads and unsigned plans where supported. Use a connected wallet for browser signing. Preserve raw integer units, exact approvals, caller authority, deadlines and receipt reconciliation. Report local checks separately from live-chain verification.