# arl:create-pool — Ammora SDK 0.3.8 Check the source for arguments and transaction requirements. [Read in Docs](https://docs.ammora.org/examples?command=arl%3Acreate-pool) · [Detailed guide](https://docs.ammora.org/guides/src-arl-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 arl:create-pool -- ` (`tsx src/arl/create-pool.ts`). Omit `--` and arguments when the source accepts none. ## Entry file: `src/arl/create-pool.ts` ```typescript import { tokenAmount, integer } from "../shared/input.js"; /** * Create a concentrated (ARL) pool and seal its first position in the same call. * * npm run arl:create-pool -- * * The price and liquidity come from the seed solver, so both budgets are consumed instead * of one being left over. `createProductionPoolLocked` then creates, wraps and permanently * locks the first position before handing it over, so there is no moment where the creator * holds it unlocked, which is what makes "locked from block zero" a property rather than a * promise. * * Run `npm run arl:plan-seed` first to see the numbers without creating anything. */ import { ammConcentratedFactoryV4CreateAbi, dammV2StaticFeeConfig, planConcentratedSeed, sqrtPriceX64FromHumanPrice, } from "@ammora-protocol/sdk"; import { address, deployment, explorerLink, reader, signer } from "../shared/env.js"; import { amount, approve, main, requireContract, tokenInfo } from "../shared/run.js"; /** * Prices on the command line are written the way a person says them: how many * quote tokens one base token costs. The pool works in raw units, so a pair * whose tokens disagree on decimals needs that gap folded in — pass the two * token decimals and the SDK does it. */ const sqrtPriceFromDecimal = ( price: string, baseDecimals: number, quoteDecimals: number, ): bigint => sqrtPriceX64FromHumanPrice(tokenAmount(price, 18), 18, baseDecimals, quoteDecimals); /** Minutes until the pool opens. Zero opens it immediately. */ const activationDelayMinutes = integer(process.env.AMMORA_ACTIVATION_DELAY_MINUTES ?? "0", "AMMORA_ACTIVATION_DELAY_MINUTES", 0, 525600); main(async () => { const [baseArgument, quoteArgument, baseAmountArgument, quoteAmountArgument, minArgument, maxArgument] = process.argv.slice(2); const baseToken = address("AMMORA_BASE_TOKEN", baseArgument); const quoteToken = address("AMMORA_QUOTE_TOKEN", quoteArgument); if (!baseAmountArgument || !quoteAmountArgument || !minArgument || !maxArgument) { throw new Error( "usage: ", ); } const { wallet, account } = signer(); const client = await reader(); const factory = deployment().contracts.launch.concentratedFactory; await requireContract(client, "base token", baseToken); await requireContract(client, "quote token", quoteToken); const [base, quote] = await Promise.all([ tokenInfo(client, baseToken), tokenInfo(client, quoteToken), ]); const baseBudget = tokenAmount(baseAmountArgument, base.decimals); const quoteBudget = tokenAmount(quoteAmountArgument, quote.decimals); const sqrtMinPrice = sqrtPriceFromDecimal(minArgument, base.decimals, quote.decimals); const sqrtMaxPrice = sqrtPriceFromDecimal(maxArgument, base.decimals, quote.decimals); const seed = planConcentratedSeed(baseBudget, quoteBudget, sqrtMinPrice, sqrtMaxPrice); console.log(`factory ${factory}`); console.log(`pair ${base.symbol} / ${quote.symbol}`); console.log(`range ${minArgument} .. ${maxArgument}`); console.log(`price ${seed.sqrtPriceX64} (sqrt, Q64.64)`); console.log(`liquidity ${seed.liquidity}`); console.log(`spends ${amount(seed.baseUsed, base.decimals, base.symbol)}`); console.log(` ${amount(seed.quoteUsed, quote.decimals, quote.symbol)}`); console.log(""); const parameters = { baseToken, quoteToken, creator: account.address, feeBps: 100, sqrtMinPrice, sqrtMaxPrice, sqrtPrice: seed.sqrtPriceX64, liquidity: seed.liquidity, activationType: 0, collectFeeMode: 0, // A pool that opens later is what a genesis vault needs: its allocation is sold // before trading starts, and the pool refuses to install one once it is active. activationPoint: Number((await client.getBlock({ blockTag: "latest" })).timestamp) + activationDelayMinutes * 60, userSalt: `0x${"00".repeat(32)}` as const, } as const; // The factory reports exactly what it will pull, so the approvals are for that and // nothing more. const [pullBase, pullQuote] = await client.readContract({ abi: ammConcentratedFactoryV4CreateAbi, address: factory, functionName: "quoteInitialLiquidity", args: [parameters], }) as readonly [bigint, bigint]; await approve( [ { token: baseToken, spender: factory, amount: pullBase }, { token: quoteToken, spender: factory, amount: pullQuote }, ], wallet, account, client, ); // The deployed V4 factory takes (parameters, feeConfig); the fee shares // moved into the controller registry. dammV2StaticFeeConfig is the flat // fee with every optional mechanism switched off. const { request, result } = await client.simulateContract({ abi: ammConcentratedFactoryV4CreateAbi, account, address: factory, functionName: "createProductionPoolLocked", args: [parameters, dammV2StaticFeeConfig(100, parameters.activationPoint)], }); const [pool, tokenId] = result as readonly [`0x${string}`, bigint]; const hash = await wallet.writeContract(request); const receipt = await client.waitForTransactionReceipt({ hash }); if (receipt.status !== "success") throw new Error(`creation reverted: ${explorerLink(hash)}`); console.log(` createProductionPoolLocked: ${explorerLink(hash)}`); console.log(`\npool ${pool}`); console.log(`position ${tokenId} is permanently locked and already in your wallet`); }); ``` ## 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) - [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.