{"_id":"@calamari-dex/sdk","_rev":"4-98023790c806e2bc39cfa34f33b5ce5a","name":"@calamari-dex/sdk","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@calamari-dex/sdk","version":"0.0.1","keywords":["ethereum","viem","dex","uniswap-v4","calamari","ink"],"license":"MIT","_id":"@calamari-dex/sdk@0.0.1","maintainers":[{"name":"goran999","email":"gutovicgoran@gmail.com"}],"dist":{"shasum":"2735b225fab97d800ae6c2e2d6363bd3614a58be","tarball":"https://registry.npmjs.org/@calamari-dex/sdk/-/sdk-0.0.1.tgz","fileCount":118,"integrity":"sha512-c66JlOGdydKinkW3uG5TCaF2O3PzO6DJAzzvMU+n2uFWGBxBL4maRmFYLZ+2ZygA/13/Z2vYIuNQZ+JzVbfsMQ==","signatures":[{"sig":"MEQCIH0FvpKG6JQQzxe8+HDHbpLXFZvcJ1w/DN+TQlsjlmwlAiBk4tG9zqSJvr4BQxeHbTgTv5HmVErm8X2emr6UgkhHtA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":928181},"main":"./dist/cjs/index.js","type":"module","_from":"file:calamari-dex-sdk-0.0.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}}},"scripts":{"test":"vitest run","build":"npm run build:esm && npm run build:cjs && node scripts/cjs-package.mjs","prepack":"npm run build","release":"npm pack --pack-destination \"${TMPDIR:-/tmp}\" && cd \"${TMPDIR:-/tmp}\" && npm publish \"calamari-dex-sdk-${npm_package_version}.tgz\" --access public","generate":"node scripts/generate.mjs","build:cjs":"tsc -p tsconfig.cjs.json","build:esm":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p test-types/tsconfig.json","prepublishOnly":"echo \"ERROR: do not run npm publish here - it stamps gitHead into the registry manifest. Use: npm run release\" >&2 && exit 1"},"_npmUser":{"name":"goran999","email":"gutovicgoran@gmail.com"},"_resolved":"/private/var/folders/fn/qdfh_59d6psbv19jlnrxymh00000gn/T/calamari-dex-sdk-0.0.1.tgz","_integrity":"sha512-c66JlOGdydKinkW3uG5TCaF2O3PzO6DJAzzvMU+n2uFWGBxBL4maRmFYLZ+2ZygA/13/Z2vYIuNQZ+JzVbfsMQ==","_npmVersion":"11.9.0","description":"TypeScript SDK for Calamari: quote, swap, and manage liquidity on the Calamari v4 DEX.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"viem":"^2.21.0","vitest":"^4.1.0","typescript":"^5.6.0","@uniswap/v4-sdk":"^2.3.2","@uniswap/sdk-core":"^7.19.1"},"peerDependencies":{"viem":"^2.21.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.0.1_1788303840950_0.21789847642135318","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@calamari-dex/sdk","version":"0.0.2","keywords":["ethereum","viem","dex","uniswap-v4","calamari","ink"],"license":"MIT","_id":"@calamari-dex/sdk@0.0.2","maintainers":[{"name":"hank97","email":"hank@hellomoon.io"},{"name":"goran999","email":"gutovicgoran@gmail.com"}],"homepage":"https://docs.calamari.trade","dist":{"shasum":"4cd2379cd9845cd605611addcac319de6e204cab","tarball":"https://registry.npmjs.org/@calamari-dex/sdk/-/sdk-0.0.2.tgz","fileCount":118,"integrity":"sha512-VBpWv3pUQOR/8Sak61UjyHmiGI94giW+z2yxMUjE3deN0IWAIhbYDE4stWbaeT1eL0C3EuUStiFgJ2B74qxedw==","signatures":[{"sig":"MEUCIB9I6Lhk3eLSLMI7y7n2yKTAWrOFr9z4i5YOrUtPxu2AAiEAxtIENeZhiXOFPEZTW+whs6k7bnfoe6kKKjIwU1paYTU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDBCrLduuKkbPtX7HjyFOCRx6IgC6JjDUFP+9rokKYwlgIgOzvCAifUMTEc1fwbjaLpoljMfQRH2hUIIfvoI6uplJI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":928518},"main":"./dist/cjs/index.js","type":"module","_from":"file:/private/tmp/calamari-sdk-baseline-20260913/calamari-dex-sdk-0.0.2.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=20"},"exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/cjs/index.d.ts","default":"./dist/cjs/index.js"}}},"scripts":{"test":"vitest run","build":"npm run build:esm && npm run build:cjs && node scripts/cjs-package.mjs","prepack":"npm run build","release":"npm pack --pack-destination \"${TMPDIR:-/tmp}\" && cd \"${TMPDIR:-/tmp}\" && npm publish \"calamari-dex-sdk-${npm_package_version}.tgz\" --access public","generate":"node scripts/generate.mjs","build:cjs":"tsc -p tsconfig.cjs.json","build:esm":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit && tsc -p test-types/tsconfig.json","prepublishOnly":"echo \"ERROR: do not run npm publish here - it stamps gitHead into the registry manifest. Use: npm run release\" >&2 && exit 1"},"_npmUser":{"name":"hank97","email":"hank@hellomoon.io"},"_resolved":"/private/tmp/calamari-sdk-baseline-20260913/calamari-dex-sdk-0.0.2.tgz","_integrity":"sha512-VBpWv3pUQOR/8Sak61UjyHmiGI94giW+z2yxMUjE3deN0IWAIhbYDE4stWbaeT1eL0C3EuUStiFgJ2B74qxedw==","_npmVersion":"11.5.1","description":"TypeScript SDK for Calamari: quote, swap, and manage liquidity on the Calamari v4 DEX.","directories":{},"sideEffects":false,"_nodeVersion":"24.5.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"viem":"^2.21.0","vitest":"^4.1.0","typescript":"^5.6.0","@uniswap/v4-sdk":"^2.3.2","@uniswap/sdk-core":"^7.19.1"},"peerDependencies":{"viem":"^2.21.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.0.2_1789347055841_0.6865226435347036","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-09-01T23:04:00.729Z","modified":"2026-09-14T00:54:47.642Z","0.0.1":"2026-09-01T23:04:01.086Z","0.0.2":"2026-09-14T00:50:55.938Z"},"license":"MIT","homepage":"https://docs.calamari.trade","keywords":["ethereum","viem","dex","uniswap-v4","calamari","ink"],"description":"TypeScript SDK for Calamari: quote, swap, and manage liquidity on the Calamari v4 DEX.","maintainers":[{"email":"hank@hellomoon.io","name":"hank97"}],"readme":"# @calamari-dex/sdk\n\nTypeScript SDK for Calamari — quote, swap, and manage liquidity on the Calamari\nv4 DEX.\n\n## Quick start\n\n```ts\nimport { CalamariClient, createPoolKey, poolId, NATIVE } from \"@calamari-dex/sdk\";\nimport { createPublicClient, http } from \"viem\";\nimport { inkSepolia } from \"viem/chains\";\n\nconst publicClient = createPublicClient({ chain: inkSepolia, transport: http(RPC) });\nconst calamari = new CalamariClient({ publicClient });\n\nconst pool = createPoolKey({\n  currencyA: NATIVE,          // sorting is handled for you\n  currencyB: USDC,\n  fee: 3000,\n  tickSpacing: 60,\n});\n\nconst state = await calamari.getPoolState(poolId(pool));\nconst quote = await calamari.quoteExactInputSingle(pool, true, 10n ** 15n);\nconst [tx] = await calamari.prepareSwapExactInSingle(pool, true, 10n ** 15n);\n```\n\n## Why this is viem-native\n\nCalamari runs **unmodified Uniswap v4** — `v4-core`, `v4-periphery` and\n`permit2` are vendored as clean upstream submodules, and the only bespoke\ncontract is a thin `V4Router` subclass wiring Permit2 payment.\n\nThis package used to re-export `@uniswap/v4-sdk`'s entity layer, on the\nreasoning that the encoding format is not ours to define. That was wrong twice\nover.\n\nIt was wrong on cost. Everything this SDK needs from that layer is a five-field\n`PoolKey`, a keccak, and an ABI encoder — it does no tick math, no liquidity\nmath, no routing. `import { Pool }` alone pulls 981KB, because the barrel\nexport reaches `v4BaseActionsParser`, which imports all of ethers v5. That is a\nJSON-RPC provider and a secp256k1/AES signing stack inside a package whose\nwhole premise is that it never signs or sends anything, sitting next to viem,\nwhich already does all of it.\n\nIt was wrong on correctness, which matters more. The struct a router decodes is\na property of *your deployment*, and an upstream encoder versions on its own\nschedule. `V4Planner.addAction` defaults to the pre-`minHopPriceX36` struct;\nthe router here reads the one with it. The mismatch did not revert — it slipped\nthe decoder's `params.length < 0x160` guard by exactly one word, read the\n`hookData` offset as a price bound, then read `hookData`'s length off\n`currency0`. Native swaps survived because that address is zero. Every\nERC20-to-ERC20 swap did not.\n\nSo the encoding is built here, against ABIs generated from the deployed\nartifacts, and `src/actions.ts` is generated from `Actions.sol`. Nothing\ndescribing the protocol is hand-written, and nothing versions independently of\nwhat is deployed.\n\nFor tick and price math, or position sizing, use `@uniswap/v4-sdk` alongside\nthis package. That is pure math, independent of any deployment, and it composes\nwith the plain types here.\n\n\n### Chain types\n\n`CalamariClient` is generic over the chain and infers it from the client you\npass, so `calamari.publicClient` hands back exactly what you gave it. That is\nload-bearing rather than cosmetic: every OP-stack chain — Ink included — ships\nformatters that widen `getBlock`'s transaction union with a `\"deposit\"` type,\nand a client typed with one of them does **not** assign to a bare\n`PublicClient`. Taking the wide type would have red-lined the snippet above on\nits first line with TS2719. `test-types/consumer.ts` compiles these shapes on\nevery `npm run typecheck` so it cannot come back.\n\n## Addresses\n\n`src/addresses.ts` is **generated from `deployments/*.json`**, never written by\nhand. Regenerate after any deploy:\n\n```bash\nforge build && npm run generate\n```\n\nContracts absent from some chains are typed optional, so consumers handle the\ngap instead of reading `undefined` off a type that promised an address. Which\nkeys are optional is derived, not declared: a key present on every deployment\nis required, and the type changes when that stops being true. `router` (the\nInkV4Router) and `positionDescriptor` are currently the optional ones — both\nanvil-only.\n\nThe books are frozen. `client.addresses` is the shared module singleton, so an\nunfrozen one would let a single consumer's mutation reach every client in the\nprocess.\n\n## Swaps\n\nAll four shapes, each with a matching quote:\n\n```ts\nawait calamari.prepareSwapExactInSingle(pool, zeroForOne, amountIn, opts);\nawait calamari.prepareSwapExactOutSingle(pool, zeroForOne, amountOut, opts);\nawait calamari.prepareSwapExactIn(route, amountIn, opts);   // multi-hop\nawait calamari.prepareSwapExactOut(route, amountOut, opts); // multi-hop\n```\n\n`slippageBps` means opposite things either way round, which is the whole\ndifference between them. Exact-input lowers a floor on what you receive;\nexact-output raises a ceiling on what you pay.\n\nTwo consequences of exact-output worth knowing. The pool takes only what the\noutput actually costs, so a native input overpays by construction: the ceiling\ngoes out as `msg.value`, and the remainder comes back via the UniversalRouter's\n`SWEEP` command, appended automatically. It has to be the router's command\nrather than the v4 `SWEEP` action, because `V4Router` does not implement that\naction and rejects it with `UnsupportedAction` — and the overpay is held by the\nrouter, not the PoolManager. Left behind it would belong to whoever swept next.\n\nMulti-hop takes a `Route` from `createRoute(currencyIn, pools, hookData?)`,\nwhich walks the pools to derive the output currency — a list that does not\nactually connect fails there rather than as an opaque on-chain revert. Only the\ntwo ends are settled; intermediate currencies net out inside the same unlock.\nHook data is per hop, so it goes to `createRoute`, not to the swap.\n\n### Per-hop price bounds\n\nThe deployed `V4Router` carries `minHopPriceX36` on every swap struct. This SDK\nsends `0` (single) and `[]` (multi), which the router reads as \"no per-hop\ncheck\"; the aggregate `amountOutMinimum` still bounds the swap end to end. A\nmulti-hop array must be either empty or exactly one entry per hop —\n`InvalidHopPriceLength` otherwise.\n\nThat field is also why these builders pass `URVersion.V2_1_1` to the planner.\n`V4Planner` defaults to the older 2.0 struct, which omits it, and the older\nencoding still *decodes* against the deployed router rather than reverting: it\nreads the `hookData` offset as the price bound and drops `hookData` entirely.\nThe quote keeps the hook data and the swap loses it, so on a hooked pool the\ntwo stop agreeing. Encode with the version the deployment actually runs.\n\n## Creating a pool\n\n`prepareCreatePool` reads the pool's state before building anything, because\nthe transaction itself cannot report failure:\n`PositionManager.initializePool` wraps `poolManager.initialize` in a try/catch\nand returns `type(int24).max` rather than reverting. Creating a pool that\nalready exists therefore *succeeds* and leaves the existing price untouched —\nso a create-then-seed batch would add liquidity at whatever price the first\ncaller chose, with nothing to signal it. `prepareCreatePoolUnchecked` skips the\nread for cases where the pool provably cannot exist yet.\n\n\n## Permit2 approvals\n\nSwap and liquidity builders do not automatically include approvals. Call\n`prepareApprovals({ owner, token, flow, amount })` first: it reads both\nallowances and returns only the missing approval transactions. Use `flow:\n\"swap\"` for swaps and `flow: \"liquidity\"` for liquidity. Send the returned\ntransactions in order and wait for confirmation before submitting the trade.\nNative inputs return an empty approval list.\n\nERC20 inputs require two grants, and **the spender differs by flow**:\n\n```ts\n// once per token\ntoken.approve(PERMIT2, MAX_UINT160)\n\n// swapping: the router spends\npermit2.approve(token, universalRouter, amount, expiration)\n\n// adding liquidity: the PositionManager spends\npermit2.approve(token, positionManager, amount, expiration)\n```\n\nA mint reverts if only the router grant exists, and a swap reverts if only the\nPositionManager grant does. For explicit control, use `prepareErc20Approve`\nand `preparePermit2Approve`; `erc20Abi` and `permit2Abi` are also exported.\nNative inputs need neither — the value rides along on the transaction.\n\n## What is not here\n\nNo tick math, no price conversion, no position sizing, and no path-finding. The\nbuilders take ticks and liquidity from you. For that math use `@uniswap/v4-sdk`\nalongside this package: it is pure and deployment-independent, and composes\nwith the plain `PoolKey` type here.\n\n## Wallets the SDK cannot drive\n\nPrivy and other embedded or MPC signers never hand over a private key, so there\nis no viem `WalletClient` to give the SDK. `prepare*` builds the transactions\nand stops there:\n\n```ts\nconst txs = await calamari.prepareSwapExactInSingle(pool, true, amountIn);\n\nfor (const tx of txs) {\n  await privyWallet.sendTransaction({ to: tx.to, data: tx.data, value: tx.value });\n}\n```\n\nSend them in order and wait for each to confirm.\n\n## Regenerating\n\n```bash\nforge build && npm run generate   # ABIs from out/, addresses from deployments/\n```\n\n## Build\n\n`dist/` is plain `tsc` output — no bundler. There is nothing to inline: the\npackage has **zero runtime dependencies**, with `viem` as a peer. `smoke.mjs`\nasserts that, because a runtime dependency creeping back is what would force\nbundling again.\n\n\n## License\n\nMIT (see `LICENSE`), with **no third-party code inlined**. Uniswap's packages\nare devDependencies only — used by `src/differential.test.ts` to prove this\nencoder is byte-identical to theirs — so npm handles their attribution\nnormally and there is no notice file to ship.\n\nThe ABIs in `src/abis/` are generated from contracts under several licenses,\nwhich are not all MIT:\n\n\n| Artifact | Source | License |\n| --- | --- | --- |\n| `poolManagerAbi` | v4-core | **BUSL-1.1** until 2027-06-15, then MIT |\n| `universalRouterAbi` | universal-router | **GPL-3.0-or-later** |\n| `positionManagerAbi`, `stateViewAbi`, `quoterAbi` | v4-periphery | MIT |\n| `permit2Abi` | permit2 | MIT |\n| `routerAbi` | `src/InkV4Router.sol` (ours) | MIT |\n\nAn ABI is an interface description rather than the implementation, and is\ngenerally treated as unprotected — but the blanket \"MIT\" this file once claimed\nwas wrong. The deployment side is a separate question: **v4-core is BUSL-1.1\nuntil 2027-06-15**, and production use before then needs the Additional Use\nGrant at `v4-core-license-grants.uniswap.eth` or a license from Uniswap Labs.\n","readmeFilename":"README.md"}