npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@logswap/sdk

v0.5.85

Published

TypeScript SDK for Logswap, the liquidity primitive introducing the logarithmic invariant — typed wrappers over the CPoolManager / FPoolManager / Router / Lens surface.

Downloads

4,409

Readme

logswap-sdk

TypeScript SDK for Logswap, the liquidity primitive introducing the logarithmic invariant — typed wrappers over the CPoolManager / FPoolManager / LogswapRouter / LogswapLens surface.

Status: identity, reads and writes for both singletons. Indexer next.

What is here now

The two things the SDK must own because they are easy to get wrong by hand, and because getting them wrong is silent:

| module | what it does | |---|---| | src/keys.ts | PoolKey and poolId = keccak256(abi.encode(key)) — market identity | | src/ids.ts | the ERC-6909 id namespace: position-class ids, token-claim ids, floor/cap packing | | src/client.ts | the handle, plus assertVersion — refuse a deployment the ABI was not built for | | src/pools.ts | market discovery from MarketCreated logs, pool state, lpEdge = F − Σ/2 | | src/positions.ts | classes, balances, claimable fees, the bit-255 position/claim split | | src/swap.ts | exact-in/out, multi-hop, and exact quotes via the revert-quoter | | src/liquidity.ts | mint, blended mint, zap, update, move, harvest, burn | | src/claims.ts | fee claims and the 6909 operator grant | | src/onboard.ts | the three approvals — ERC-20 → Permit2 → router, and the 6909 grant |

Both are computed offline — no RPC, no deployment needed to address a market or a position.

Reading a holder's book

  • positionsOf(c, key, owner) — the uncapped book in one lens call (the ladder bitmap enumerates floors; an uncapped id is a pure function of the floor).
  • holdingsOf(c, key, owner) — the complete book, capped classes included: replays ClassRegistered (every class is registered once, with its floor and cap) and checks the owner's balance on each. Use this for "my positions"; a capped mint is invisible to positionsOf.
  • getHolderPosition(c, key, owner, floor, cap?) — one class by (floor, cap); move(...) / update(...) / harvest(...) / burn(...) / claimFees(...) act on it.
  • F side: discoverFPools(c) (shape, and the block the pool was initialized in), getFPool, fPoolShareBalance, fPoolShareValue; previewZapIn reads the lens (the router's F flows live in a facet, its previews moved to the lens). Since F version 25 every F state read goes through the lens (fPool, getFPools, fBundleOf, fDividendOf, fLienOf): the manager's typed views are behind extsload (decisions 062), and the lens decodes them with the contracts' FPoolState, so the SDK never hard-codes the storage layout.
  • F pool state names (F version 25): swapFee (was phi), logFloor θ — the log of the current floor price (was theta), refLogFloor θ₀ — the reference floor income counts from (was theta0), cap (d in 1e-6 log units, 0 uncapped), and per leg virtualReserves and kappa.

Who may create what: the gate, the menus (C version 7, F version 26)

Since logswap-contract #60 (decisions 064–065) creation is curated at launch, on both managers:

  • The C gate is the public policy, set in the C manager's constructor. A C market is admitted if its creator, quote, pair, swap-fee tier (2, 5, 10, 25, 50, 100 bp) and tick spacing (10 or 100 bp) are listed, and only one market per (base, quote, fee) exists. cGateRules(c, { key, creator }) reads every check in one round; gateErrorAbi decodes the refusals (CreatorNotListed, MarketExists, SpacingNotListed, PairNotListed, NoForwardedUser, PadExists).
  • createMarket stays one transaction: the router is a trusted forwarder, so the gate checks the router's user() — the wallet that sent the call — against the creator list.
  • The mint fee is a key field (C 12 / F 38, decision 078): the creator's pick, fixed for the pool's life and part of its id (PoolKey.mintFee, FPoolKey.mintFee; mintFee? on fPoolInitialize / fPoolLaunch). The managers require 2 * swapFee <= mintFee <= MINT_FEE_MAX (2%) and revert BadParam; isValidMintFee, minMintFee and MINT_FEE_MAX are exported, and presetMintFee(swapFee) is the least the managers accept, twice the swap fee. initialize, initializeMarket and createMarket take no separate argument, the policies keep no menu, and C's getPool no longer returns it (read key.mintFee; getFPool(...).mintFee still reads an F pool's). mintFee(p, x, rate) previews it at the market's rate.
  • A fee of 0 is no fee: swapFeeOf and DEFAULT_FEE are gone; marketSwapFee returns the key's own fee for an initialized market.
  • C reads: getPool reads the lens's getPools; getPositionClass reads the class through extsload at CPoolState's slot (the manager's typed views are gone).
  • Creators are curated on every kind at launch (onboarding under a service agreement); the LOG Authority's helpers: policySetCreatorListed, gateSetPairListed, gateSetSpacingListed, gateSetForwarderTrusted, setCGate.
  • Two roles (decision 066, C 8 / F 27). logAuthority() reads the LOG Authority (the registry's logAuthority; proposeLogAuthority / acceptLogAuthority), which administers the registry, both managers and every policy. logTreasury(side) reads a manager's treasury, which only receives; proposeTreasury is the authority's, acceptTreasury the incoming treasury's own call. collectCProtocolFees(key) may be sent by anyone and pays the treasury. The C swap-fee tax is each market's from birth (getPool(key).swapFeeTax, cMarketSwapFeeTax); setCSwapFeeTax sets the gate's level for markets born after it; the C gate is fixed (setCGate throws). registryOwner, registryProposeOwner / registryAcceptOwner and proposeCollector / acceptCollector remain as deprecated aliases.

History from the indexer (indexer phase 1)

Every event read goes through getEventLogs (one event) or getEventsLogs (several, tagged by eventName): the rindexer GraphQL endpoint when one is given, the node otherwise or when it fails. Since logswap-be #43 the indexer also holds the four policies (one Policy table per event, tracked from the registry's Approved), the registry, the token factory and the managers' admin events, so nothing has to scan the node from block 0 — which the devnet node, pruning logs after about a day, answers only partly.

  • swapFees, holdingsOf, discoverMarkets and fPoolKeyOfPool take indexer (the salt is not in PoolCreated, so a pad's key is still rebuilt from its split with nonce 0).
  • getEventLogs takes several emitters (address: [...]); a policy outside the artifact names its shared tables with contract: indexedContractOf(kind, event) (or kind on getEventsLogs).
  • tokensCreated lists the factory's tokens (addresses.tokenFactory): the token list's provenance.

Indexer views (indexing phase 2)

The indexer also serves derived views (logswap-be devnet/VIEWS.md), joining its event tables with the snapshotter's state. views.ts reads each as typed rows: amounts as bigint, prices, APYs and progress as number, times as unix seconds. Every reader takes the GraphQL endpoint and a { condition, filter, orderBy, first, signal } query, and pages by offset.

| Reader | View | What a row is | | --- | --- | --- | | poolDirectory | allPoolDirectories | a pool of either manager, its kind and birth | | eventUsers | allEventUsers | a manager event and who did it (the router's caller when routed) | | poolHolders | allPoolHolders | a current ERC-6909 balance, with C's backstop and F's dead shares flagged | | walletPositions | allWalletPositions | a wallet's holding; F valued at the latest share value | | walletPoolFlows | allWalletPoolFlows | a wallet's in/out, fees and dividends per pool | | swapFlows | allSwapFlows | a swap's volume and fee in quote | | priceTicks | allPriceTicks | a price point per (pool, base) | | candles(url, "minute" \| "hour" \| "day") | allCandle…s | OHLC with volume and fees | | poolTvlHours | allPoolTvlHours | the hour's last snapshot: TVL, liquidity | | poolSummaries | allPoolSummaries | 24 h / 7 d volume, fees, APY; latest TVL | | generationSteps | allGenerationSteps | a generation step and the split of the income it released | | padStatuses | allPadStatuses | each pad and POL now, with the next threshold and progress | | protocolRevenueDays | allProtocolRevenueDays | protocol revenue per day and source |

Given an indexer, three functions now take their figure from a view and keep their previous path as the fallback, with the same answer on the same data:

  • holdingsOf: the owner's held class ids from pool_holder, then the lens as before;
  • fPoolShareHolders: the holders from pool_holder;
  • swapFees: the window from swap_flow.

What stays a live read: a C position's value and every unclaimed fee or dividend (the lens: legsOf, heldByIds, fDividendOf). They accrue without events, so no view holds them.

The F pool's life: four calls (F 38)

  • fPoolInitialize creates an unfunded pool. Its key is (quote, bases, swapFee, policy, creator, salt, mintFee): no weights and no cap, and the set of bases is fixed for the pool's life.

  • fPoolDeploy (deployLiquidity, decisions 083, 084) is the authority's and SETS THE BOOK. Each baseAssets[j] is the TOTAL base reserve of asset j after the call (0 leaves it out) and the price that values it (priceX36), quoteAmount is the total bid, and the manager settles the difference with the caller: a larger total is pulled, a smaller one is pushed to to, so one call replaces an asset by another. Pass the book outright (baseAssets, lnCapOverSeed) or the sponsor's terms (bases, weights, L0 and the wanted marks x0 or the reserves r0; fPoolBook builds the book). On an UNFUNDED pool (new, or after fPoolClose) it funds the first or next generation. On a LIVE pool it is a regeneration that sets the book: income settles to to, every holder but the carried ones is frozen into the closing generation's bundle (fPoolRedeem), and the carried book becomes the one named. A pad is forward-only (PadForwardOnly): it uses fPoolRegenerate.

  • fPoolRegenerate is the same routine with nothing changed: the generation step, the pad's graduation.

  • fPoolClose harvests the bid out and closes the pool at an empty bid; the pool keeps its id and every role.

  • The cap (decisions 061, 075) is the pool's one log ratio lnCapOverSeed = ln(cap price / seed price) in 1e-6 log units, chosen at each deployment: each asset's maximum price is its own seed price times it. fPoolCapOfLeverage(λ) gives it for a leverage (λ = 2 → the cap at twice the seed price), fPoolLeverageOfCap(d) the inverse, and fPoolCapK(d) = e^{−d} the constant that scales each reserve by (1 − k) and divides the base value by (1 − k) to give the liquidity. A pad is uncapped (PadUncapped).

  • LiquidityDeployed echoes the deployment: (quoteAmount, baseAssets, lnCapOverSeed). fPoolBookWeights and fPoolBookL derive the allocation and the liquidity from it. A regeneration emits no such event; the freeze-out is read from GenerationRetired and IncomeReleased.

  • Income and income tax (decision 085): the dead shares' dividend and the share of it the treasury takes are the income and the income tax (IncomeReleased, incomeHeld, incomeTax, padSetIncomeTaxRate).

  • The lien (decisions 063): a lending contract locks an owner's shares in place. fPoolApproveShares (the owner's per-id allowance), fPoolLock / fPoolUnlock (the locker's; to = owner is a release, anyone else a seizure), fPoolBankLien (bank the locked dividend now), fPoolLienOf (locker, amount, and the dividend the lien holds). The dividend the locked amount earns is held by the lien: a repaid loan gets it back, a seizer takes it.

Chains and deployments (F version 29)

log(swap) releases on Ethereum (1), Base (8453), Arbitrum One (42161) and Robinhood Chain (4663), with Robinhood Chain Testnet (46630) for testing. The contracts are deployed through CreateX (CREATE3, contracts decision 069) at the SAME addresses on every chain, so an address names a contract only together with a chain id.

  • LOGSWAP_CHAINS (src/chains.ts): one entry per chain — the viem chain, network (the artifact's), nativeCurrency, explorer, publicRpc (rate-limited), devnet, testnet, the verified quotes (symbol, address, decimals) and padQuote, and maxLogRange. Also 31337 (local anvil) and 31339 (the devnet). logswapChain(id), quoteOf(id, "USDC"), RELEASE_CHAIN_IDS.
  • LogswapDeployment is the contracts' deployments/<chainId>.json (DeployChain.s.sol; the local DeployLocal artifact has the same fields plus its devnet extras). deploymentFromArtifact(json, { chainId }) validates it and refuses an artifact for another chain; LOGSWAP_DEPLOYMENTS / deploymentFor(id) hold the published ones (none yet: nothing is deployed on the release chains).
  • createLogswapClient({ public, deployment, indexerUrl }) takes the addresses from the deployment and keeps its chainId and deployBlock; addresses still works on its own.
import { createPublicClient, http } from "viem";
import { createLogswapClient, deploymentFromArtifact, logswapChain } from "@logswap/sdk";

const chain = logswapChain(8453)!;
const c = createLogswapClient({
  public: createPublicClient({ chain: chain.chain, transport: http(process.env.BASE_RPC_URL) }),
  deployment: deploymentFromArtifact(artifactJson, { chainId: 8453 }),
  indexerUrl: "https://…/graphql", // this chain's indexer
});

What changes for readers:

  • Log scans start at deployBlock where they started at block 0 (discoverMarkets, discoverFPools, fPoolKeyOfPool, holdingsOf, fPoolShareHolders, getEventLogs, getEventsLogs); an explicit fromBlock still wins.

  • The chain path is chunked: eth_getLogs over spans of maxLogRange blocks (2 000 on the release chains, per-client override), at most four in flight (getLogsChunked). Public RPCs refuse an unbounded range.

  • The indexer is per chain: indexerUrl on the client is the default indexer of every history read and of discoverMarketsBest. Its rows are filtered by contract address, which is the same on every chain, so one URL must serve one chain.

  • Caches key on the chain id: the policy-kind cache asks the node for the chain id when the client has none; RESETTABLE_CHAINS is every registry chain flagged devnet (plus 1337 and 31338), extended with addResettableChain.

  • F version 29 (decision 068): FPoolState.restructureTime (unix seconds; was restructureBlock), registrySunset(c, policy, untilTime) and RegistryEntry.until are timestamps. EXPECTED_F_VERSION is 29.

  • F version 31 (decision 072): DividendClaimed carries the generation (gen, indexed); lock and unlock emit LienLocked / LienUnlocked, so a lien is readable from the log stream with getEventLogs. EXPECTED_F_VERSION is 31.

Conventions

  • The SDK hides the manager/router/lens split. Which contract hosts which action is currently decided by EIP-170 headroom, not by design — so a future re-homing must be an SDK patch, not a breaking change for consumers.
  • Zero is not the default. A swapFee of 0n (phi before C version 6) resolves to DEFAULT_FEE at read time, so a key carrying 0n and one carrying the resolved value are different markets with different ids. Always address a market by the key it was initialized with.
  • Split every ERC-6909 Transfer on bit 255. Clear means a token claim, not a position; an indexer that ignores this reports phantom LP positions for market makers parking inventory.

Install

npm i @logswap/sdk viem

Published as @logswap/sdk from v0.5.35; earlier versions used another name.

viem is a peer dependency. The package ships dist/ plus src/, including the generated ABIs, so the contract surface it was built against travels with it.