# arl:add-liquidity-and-lock — Ammora SDK 0.3.8 Check the source for arguments and transaction requirements. [Read in Docs](https://docs.ammora.org/examples?command=arl%3Aadd-liquidity-and-lock) · [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:add-liquidity-and-lock -- ` (`tsx src/arl/add-liquidity-and-lock.ts`). Omit `--` and arguments when the source accepts none. ## Entry file: `src/arl/add-liquidity-and-lock.ts` ```typescript import { tokenAmount } from "../shared/input.js"; /** * Top a concentrated position up, then lock what was added. * * npm run arl:add-liquidity-and-lock -- * * Two transactions, so between them the added liquidity is briefly withdrawable. The * position is yours, so that window only matters if you are proving the commitment to * someone else. For a first position, createProductionPoolLocked does both at once. */ import { DammV2Client } from "@ammora-protocol/sdk"; import { clientOptions, address, deployment, reader, signer } from "../shared/env.js"; import { amount, approve, asPool, main, requireContract, send, tokenInfo } from "../shared/run.js"; main(async () => { const [poolArgument, tokenIdArgument, baseArgument, quoteArgument] = process.argv.slice(2); const pool = address("ARL_POOL", poolArgument); if (!tokenIdArgument || !baseArgument || !quoteArgument) { throw new Error("usage: "); } const tokenId = BigInt(tokenIdArgument); const { wallet, account } = signer(); const client = await reader(); const contracts = deployment().contracts.launch; await requireContract(client, "pool", pool); const sdk = new DammV2Client( client, pool, "concentrated", contracts.concentratedFactory, contracts.concentratedPositionManager, clientOptions(), ); const state = await asPool(pool, "a concentrated pool", () => sdk.getPoolState()); const [base, quote] = await Promise.all([ tokenInfo(client, state.baseToken), tokenInfo(client, state.quoteToken), ]); const maximumBaseAmount = tokenAmount(baseArgument, base.decimals, true); const maximumQuoteAmount = tokenAmount(quoteArgument, quote.decimals, true); const before = await sdk.getManagedConcentratedPosition(tokenId) as { unlockedLiquidity: bigint }; console.log(`pool ${pool}`); console.log(`position ${tokenId}`); console.log(`adding up to ${amount(maximumBaseAmount, base.decimals, base.symbol)}`); console.log(` up to ${amount(maximumQuoteAmount, quote.decimals, quote.symbol)}`); console.log(""); const plan = await sdk.planAddLiquidityToManagedConcentratedPosition({ tokenId, caller: account.address, maximumBaseAmount, maximumQuoteAmount, slippageBps: 100, deadline: BigInt(Math.floor(Date.now() / 1000) + 600), }); await approve(plan.approvalRequirements, wallet, account, client); await send("addLiquidity", plan.transaction, wallet, account, client); // Lock exactly what this run added, leaving anything unlocked beforehand as it was. const after = await sdk.getManagedConcentratedPosition(tokenId) as { unlockedLiquidity: bigint }; const added = after.unlockedLiquidity - before.unlockedLiquidity; console.log(`\nadded ${added} of unlocked liquidity`); if (added <= 0n) { console.log("nothing was added, so there is nothing to lock"); return; } await send( "permanentLockPosition", await sdk.planPermanentLockManagedConcentratedPosition(tokenId, added, account.address), wallet, account, client, ); }); ``` ## 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.