# @ammora-protocol/sdk

TypeScript SDK for the [Ammora protocol](https://github.com/ammora-labs/ammora-protocol) — reusable EVM
liquidity infrastructure for token launchpads (bonding-curve launches, concentrated/compounding AMMs, ALMM
bin pools, genesis vaults, presales, vaults, and routers).

> **Beta testnet software.** The qualified GIWA release is live on GIWA Sepolia, but Ammora has not
> announced a mainnet deployment or completed an independent security audit. ABIs and builder signatures
> may change between 0.x releases. Do not use with real funds without your own review.

## Install

```sh
npm install --save-exact @ammora-protocol/sdk@0.2.13 viem
```

The published SDK, Landing and standalone examples pin `0.2.13`. Pin both the reviewed
package and deployment manifest for reproducible integrations. Package publication does not
deploy a contract, register an indexer source, or update an application. This release includes
`classifyAmmoraV4ExactInputFill` and the reviewed GIWA legacy/native route catalog used to keep
older Factory generations compatible without trusting an arbitrary pool.

## V4 receipt and migration patch

- Config, Launch, Swap and Migrated receipt parsers check the decoded event name
  before applying event-specific validation. Emitter, successful-receipt, policy
  and swap-plan checks remain in place. Mixed-event receipts must not return an
  incomplete Config identity or reject a valid event because of an unrelated log.
- `AmmoraV4LaunchCurveClient.planMigrateAtBlock(blockNumber)` is an additive API.
  It reads authentication and migration state at the specified bigint block,
  without selecting another head or reusing/updating the legacy authentication
  cache. Existing `planMigrate()` behavior remains compatible. Read the
  [snapshot, cache and execution safety contract](docs/v4-migration-planning.md).
- `RevenueCenterClient.resolveReceipt()` already exists. The ARL FeeVault path
  returns the first matching canonical `ClaimedFor` amount, permits an explicit
  zero when `minimumAmount` is zero, and excludes the `Claimed` alias. It is not
  a batch sum, finality verifier, or proof that the payout was positive. See the
  [claim receipt examples and trust boundary](docs/revenue-receipts.md).

These changes do not alter deployed contracts or certify mainnet readiness.

## Final fill and Graduation

A V4 launch ending with unused exact-input is not necessarily a liquidity error. For a
quote-token to base-token buy, the terminal curve fill consumes the remaining amount and
returns `amountLeft` to the payer. The curve then becomes `ReadyToMigrate`; creating the
ARL pool is a separate permissionless `migrate()` transaction.

```ts
const quote = await curveClient.quoteExactInputAtBlock(maximumInput, false, blockNumber);
const fill = classifyAmmoraV4ExactInputFill(quote, false);

const plan = await curveClient.planSwapExactInput({
  includedAmountIn: maximumInput,
  baseForQuote: false,
  allowPartialFill: fill.allowPartialFill,
  slippageBps: 100,
  recipient,
  deadline,
});
```

Keep ordinary orders strict. `classifyAmmoraV4ExactInputFill` returns
`allowPartialFill=true` only for `graduation-boundary`; a partial sell is not Graduation.
Reconcile the confirmed Swap receipt, show the returned amount, and enqueue
`planMigrateAtBlock(receiptBlock)` in an idempotent operator service. Simulate again immediately
before sending and reconcile hash, nonce, receipt, canonical block and canonical pool before
retrying. A native router returns unused `msg.value` in the same final-fill transaction.

If the helper returns `terminal-dust`, do not submit the user's zero-output trade. Show a short
liquidity-transition state and invoke the reviewed operator runbook; the SDK never performs a
state-changing dust recovery automatically.

See the [complete lifecycle guide](docs/v4-graduation-lifecycle.md) and the runnable
[`launch:graduate` example](../../examples/src/launch/final-fill-and-graduate.ts).

## What it provides

- **ABIs** for every deployable protocol component (`launchFactoryAbi`, `dlmmBinPoolAbi`,
  `ammAlphaVaultAbi`, `ammoraDynamicVaultAbi`, …), kept drift-gated against the audited contract surface.
- **Calldata builders** (`buildCreateLaunch`, `buildBuyExactIn`, `buildDepositAlphaVault`,
  `buildDlmmZapIn`, …) returning `{ data }` ready for any EVM transaction stack.
- **Quote / planning helpers** (slippage math, DLMM multi-position planner, curve builders re-exported
  from [`@ammora-protocol/math`](https://www.npmjs.com/package/@ammora-protocol/math)).
- **Connection-backed clients** for ALMM/DLMM, DAMM V2, segmented DBC, and dynamic fee sharing.
  They read live pool/config/vault state, obtain execution quotes, bind slippage, and plan ERC-20 approvals.

Offline builders remain address-agnostic. The built-in GIWA catalog remains available as a compatibility
route. New integrations should load the qualified release manifest, create an isolated deployment source,
attest its runtime hashes during bootstrap, and inject the verified source into connected clients.

## Launchpad discovery

Launches and pools are dynamic data; they are not copied into each SDK release. A compatible launchpad
creates through an Ammora-reviewed factory, the Data API indexes its canonical events, and every SDK
consumer discovers the result through the same typed client:

```ts
import { AmmoraDataApiClient } from "@ammora-protocol/sdk";

const data = new AmmoraDataApiClient("https://ammora-giwa-sepolia-data.fly.dev");
const launches = await data.getLaunches({ chainId: 91_342n });
const launch = await data.getLaunch(91_342n, tokenAddress);
```

Registering another token or pool therefore does not require republishing the SDK. An SDK release is
needed only when the reviewed contract catalog, ABI, transaction builder, or typed API surface changes.
Partner factories are admitted separately after chain ID, deployment block, runtime code hash, and event
compatibility review; the indexer backfills that factory from its registered start block before treating
its history as complete.

## Example

```ts
import {
  attestAmmoraDeployment,
  buildCreateALCSegmentedV3LaunchWithTokenConfig,
  createAmmoraDeploymentSourceFromReleaseManifests,
  type AmmoraReviewedReleaseManifestV1,
} from "@ammora-protocol/sdk";

const manifest = await loadReviewedManifest() as AmmoraReviewedReleaseManifestV1;
const candidate = createAmmoraDeploymentSourceFromReleaseManifests([manifest]);
const verified = await attestAmmoraDeployment({
  source: candidate,
  chainId: manifest.chainId,
  providers: [{ id: "primary", client: publicClient }],
});
const deployment = verified.profile.active;
const tx = buildCreateALCSegmentedV3LaunchWithTokenConfig(
  "My Token",
  "MTK",
  "ipfs://token-metadata",
  "ipfs://creator-metadata",
  configId,
  9,
  poolCreationFee,
);

await walletClient.sendTransaction({
  account,
  to: deployment.launch.factory,
  data: tx.data,
  value: tx.value,
});
```

Read `configId`, token decimals, and `poolCreationFee` from the enabled config before submission; for
production UI, prefer `ALCClient.planLaunchWithTokenConfigFromConfig`, which binds those live values.

## Reviewed GIWA deployment

The qualified GIWA release is represented by one versioned manifest containing chain ID `91342`, active
addresses, recognized factory history, address-level start blocks, and runtime code hashes. Keep that
manifest in application-owned release configuration; do not copy a partial address list into source code.

```ts
import {
  ALMMFactoryClient,
  attestAmmoraDeployment,
  createAmmoraDeploymentSourceFromReleaseManifests,
  type AmmoraReviewedReleaseManifestV1,
} from "@ammora-protocol/sdk";

const manifest = await loadReviewedManifest() as AmmoraReviewedReleaseManifestV1;
const candidate = createAmmoraDeploymentSourceFromReleaseManifests([manifest]);
const verified = await attestAmmoraDeployment({
  source: candidate,
  chainId: manifest.chainId,
  providers: [{ id: "primary", client: publicClient }],
});
const contracts = verified.profile.active;
const factory = new ALMMFactoryClient(
  publicClient,
  contracts.liquidityMarketMaker.factory,
  { deploymentSource: verified.source },
);
```

Runtime attestation is an explicit bootstrap operation; quote and transaction-plan methods never perform it
implicitly. A high-volume service should use independently reviewed providers and retain the attestation
evidence before enabling writes.

## Custom reviewed deployment source

Custom source support is structural portability, not a claim that every EVM chain is production-ready.
The SDK supports additive custom deployment sources, but each additional EVM chain requires an independent
deployment, runtime attestation, lifecycle, indexer, and rollback qualification before production use.

An application can prepare an isolated, immutable catalog for another reviewed EVM deployment without
changing Ammora's built-in GIWA catalog. Keep the full contract map and runtime-hash evidence in an
application-owned release manifest:

```ts
import {
  attestAmmoraDeployment,
  createAmmoraDeploymentSourceFromReleaseManifests,
  type AmmoraReviewedReleaseManifestV1,
} from "@ammora-protocol/sdk";

const manifest = await loadReviewedManifest() as AmmoraReviewedReleaseManifestV1;
const candidate = createAmmoraDeploymentSourceFromReleaseManifests([manifest]);
const verified = await attestAmmoraDeployment({
  source: candidate,
  chainId: manifest.chainId,
  providers: reviewedProviders,
});

const resolved = verified.profile;
const deploymentSource = verified.source;
```

`createAmmoraDeploymentSourceFromReleaseManifests` validates and freezes manifest structure but performs
no RPC calls. `attestAmmoraDeployment` then verifies the RPC chain ID and every declared runtime code hash.
Connected clients accept `verified.source` through the optional `deploymentSource` field. Omitting that
field retains the existing built-in GIWA compatibility route and byte-identical legacy transaction-plan
behavior.

For strategy liquidity, use the connected client so the transaction includes both an active-bin movement
bound and a minimum LP-share amount for every bin:

```ts
import { ALMMClient } from "@ammora-protocol/sdk";

const almm = new ALMMClient(publicClient, pool, positionManager, binLens);
const { transaction, quote } = await almm.planCreateStrategyPosition({
  lowerBinId: -10,
  upperBinId: 10,
  totalBaseAmount: 1_000_000n,
  totalQuoteAmount: 1_000_000n,
  strategy: 0,
  shareSlippageBps: 50,
  maxActiveBinSlippage: 2,
  recipient,
  deadline,
});

// Execute approvalRequirements first, then send transaction.
console.log(quote.activeId, quote.minimumShares);
```

ALMM swap quotes follow the current DLMM fee shape: `fee` is the provider/order-participant amount after
the protocol share is removed, and `protocolFee` is returned separately. Both exact-input and exact-output
quotes require the deployed `ALMMBinLens`. DAMM V2 connected quotes return `executionPriceX128` and
`priceImpactBps`, where impact compares the actual execution price with the pre-swap spot price rather than
using sqrt-price movement. Detailed DAMM quotes expose `totalFee`, `feeToken`, and the complete protocol,
protocol2, referral, creator, LP/claiming, and compounding split. Typed pool creation supports balanced and
concentrated single-side initialization. Balanced creation derives both initial sqrt price and liquidity from
the supplied base/quote caps. The connected creation planner additionally rejects unsupported token policy,
an occupied canonical pool key, and a production factory without its fee controller before returning a
transaction. `DammV2Client` also exposes compounding merge/lock/delegate and concentrated position-manager
claim/merge/vesting/close operations.

Explicit read-only factory profiles remain binding even with a custom deployment
source. See [DAMM execution profiles](docs/execution-policy.md) for connected
planner checks and the limits of legacy synchronous calldata helpers.

Connected receipt resolvers bind execution results to the next step: `ALMMClient.resolvePositionCreation`
checks the emitted pool, owner, and range for funded strategy positions, while
`DammV2Client.resolveAddedLiquidityPosition` checks the pool, owner, and positive liquidity before exposing
the new DAMM V2 position ID to fee-sharing or follow-up liquidity flows.

Fee settlement is exposed with the same separation as the contracts. `ALMMClient.getProtocolFeeState` and
`planClaimProtocolFee` read and claim the configured DLMM protocol liability, while
`buildClaimALMMProviderFee` remains the direct-bin provider path and position fees are claimed through
`planClaimPositionFees`. `buildClaimFeeVault` handles a beneficiary's direct DBC/DAMM external-fee claim;
`buildClaimFeeVaultFor` is reserved for beneficiary/delegate routing.

For initial DLMM liquidity use `planSeedLiquidity` or `planSeedLiquiditySingleBin`. These create a locked
bootstrap position with explicit fee owner and operator instead of an ordinary removable strategy position.
`planAddLiquidityByWeight` preserves the exact input totals across arbitrary bin weights and returns every
required manager approval. `ALMMFactoryClient.planCreatePoolFromPreset` reads the live preset, rejects
disabled presets, canonicalizes token order and active ID, and checks token policy, deterministic prediction,
lifecycle constraints, and canonical-key duplication before returning calldata. Strategy quotes reject any
zero-share bin rather than returning a transaction that will revert opaquely.

The segmented DBC V3 registry surface is exported as `segmentedALCConfigRegistryV3Abi`, with
`buildRegisterALCSegmentedConfigV3` and `buildSetALCSegmentedConfigV3Enabled`. DBC config validation enforces
the 16-segment limit, 20 bps protocol migration fee, 10% one-day lock, and two-year vesting maximum.
`ALCClient.listConfigs` provides bounded, cursor-based enumeration of immutable registry configurations
(64 records per call at most) and excludes disabled configurations by default, so applications do not need
to accept a raw config ID from the user.
For pre-pool launch previews, `quoteALCSegmentedExactInput` and `quoteALCSegmentedExactOutput` bundle
segmented traversal with fee scheduling, first-swap minimum fee, dynamic fee, collect-fee mode, and the
buy-only rate limiter.
`buildCreateALCSegmentedV3LaunchWithTokenConfigAndBuy` atomically creates a 6–9 decimal token and executes
one or two first buys through the deployed `ALCSegmentedFirstBuyExecutorV3`. Pass that executor address to
the builder and approve the quote token to the executor (not the launch factory) before sending the
`createLaunchAndCall` transaction. The connected
`planLaunchWithTokenConfigAndBuyWithApproval` method reads the enabled registry config and returns that
executor approval automatically. The factory pins the executor runtime code hash when governance approves
it and rechecks the hash at launch time; the connected client also requires the executor's live code,
factory binding, callback approval, and registry binding to remain valid. All low-level segmented DBC launch
builders require an explicit `poolCreationFee`; there is no zero-fee default.

After sending `buildRegisterALCSegmentedConfigV3`, pass the successful transaction receipt to
`ALCClient.resolveConfigRegistration`. The helper accepts exactly one `ConfigRegistered` event from the
configured registry and verifies its config hash, quote token, and enabled state against current on-chain
storage. `planLaunchWithTokenConfigFromRegistration` and
`planLaunchWithTokenConfigAndBuyFromRegistration` then bind that verified config ID directly into the
launch transaction. DBC swap planners expose both the compatibility `approvalRequirement` field and the
common `approvalRequirements` array.

DFS integrations should use the source-specific atomic funding builders for delegated DBC FeeVault claims,
compounding fees, concentrated single-token fees, and position rewards. `DFSClient` returns the approval or
delegate setup transactions required by each source. Capped balance/allowance funding is available through
`buildFundAFSVaultUpTo`, and a recipient can route its own payout with
`buildClaimAmmoraSharedFeeTo`. `DFSFactoryClient` checks the factory's live token policy and deterministic
sender-bound address before building creation calldata, rejects an occupied salt, and enforces 2–5 unique
recipients with nonzero individual and aggregate shares bounded by `uint32`. Direct funding is also
fail-closed against the current token policy. Generic FoT, sender-fee, rebasing, callback, and unclassified
tokens are rejected; an explicitly classified recipient-fee token is settled as gross liability, with
receiver net credit emitted separately.

The disposable Anvil drill executes the built SDK against freshly deployed contracts and checks fee
liability-to-balance conservation for DBC, DLMM, DAMM V2, and every DFS source:

```sh
npm run local:onchain:drill --workspace @ammora-protocol/sdk -- --port 58553
```

See [Phase 81](../../docs/PHASE_81_METEORA_POST_FIX_REAUDIT.md) for the current official-revision,
liquidity, launch, and security parity matrix.

## Public ARL V5 development (unreleased)

`ArlV5FactoryClient` and `ArlV5PoolClient` implement the 2026-09-18 permissionless
creation design: caller-funded pools, fixed compounding/limits, delayed fee patches,
and action-scoped execution policies. No partner registration or certification is required.
See [public V5 integration](docs/arl-v5.md). These exports are local unreleased work,
not features of the already-published `0.2.11` package. No public V5 catalog is enabled;
active V4 addresses/calldata are unchanged.

The earlier Registry/Adapter-based clients remain only for experimental compatibility
and regression testing. Their [historical intake instructions](docs/partner-graduation.md)
do not apply to public V5 creation.

## License

MIT — see [LICENSE](./LICENSE). Distribution includes
[THIRD_PARTY_NOTICES.md](./THIRD_PARTY_NOTICES.md); read it before commercial use.
