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

@compx/sdk

v2.1.4

Published

TypeScript SDK for the CompX platform on Algorand: staking, lending, payments, and clAMM (coming soon)

Readme

CompX SDK

TypeScript SDK for the CompX platform on Algorand. One package, multiple domains: staking, lending, payments, and clAMM (coming soon).

Domain support

| Domain | Client | Status | What it covers | |--------|--------|--------|----------------| | Lending | sdk.lending | Supported | Markets, APY/LST pricing, oracle prices, user & debt positions | | Staking | sdk.staking | Supported | Pool state, staker records, annualized APR estimates | | Payments | sdk.payments | Supported | Waypoint route discovery/reads, fee tiers, and vesting/claimable calculations | | clAMM | sdk.clamm | Coming soon | Concentrated-liquidity AMM (placeholder; not yet usable) |

The SDK is read- and calculation-focused: it reads on-chain state and computes derived values without a wallet. Transaction signing (deposit, stake, route creation, etc.) is performed in the application layer with a connected signer.

Installation

npm install @compx/sdk
# or
pnpm add @compx/sdk
# or
yarn add @compx/sdk

algosdk is a peer dependency:

npm install algosdk

Quick Start

import { CompXSDK } from '@compx/sdk';

// The simplest setup: just pick a network. The SDK defaults to the public
// Nodely Algod endpoint for that network.
const sdk = new CompXSDK({ network: 'mainnet' });
import { CompXSDK } from '@compx/sdk';
import algosdk from 'algosdk';

// Or supply your own Algod client (custom node, token, port)
const algodClient = new algosdk.Algodv2(
  '',                                      // API token (empty for public nodes)
  'https://mainnet-api.algonode.cloud',    // Algod URL
  ''                                       // Port
);

const sdk = new CompXSDK({
  network: 'mainnet',           // Required: 'mainnet' or 'testnet'
  // algodClient,               // Optional: defaults to the Nodely endpoint for the network
  // indexerClient,             // Optional: for historical queries
  // masterRepoAppId,           // Optional: override Master Repo registry app ID (defaults per network)
  // payments: { registryAppId, fluxOracleAppId }, // Optional: payments config
});

// Lending (no wallet needed)
const market = await sdk.lending.getMarket(12345678);
console.log('Supply APY:', market.supplyApy);

// Staking (no wallet needed)
const pool = await sdk.staking.getPool(23456789);
console.log('Total staked:', pool.totalStaked.toString());

// Payments (pure calculations)
const fee = sdk.payments.estimateRouteFee(1_000_000n, 31566704n, 0, 31566704n);
console.log('Route fee:', fee.toString());

You can also construct any domain client on its own:

import { LendingClient, StakingClient, PaymentsClient } from '@compx/sdk';

const lending = new LendingClient({ algodClient, network: 'mainnet' });
const staking = new StakingClient({ algodClient, network: 'mainnet' });
const payments = new PaymentsClient({ algodClient, network: 'mainnet' }); // registry/flux default per network

Configuration

CompXSDK accepts a single CompXSDKConfig:

| Field | Required | Description | |-------|----------|-------------| | algodClient | No | Pre-configured algosdk.Algodv2 client. Defaults to the public Nodely endpoint for network | | network | Yes | 'mainnet' or 'testnet' | | indexerClient | No | algosdk.Indexer for historical queries | | masterRepoAppId | No | Master Repo registry app ID for on-chain market and pool discovery (defaults to the known app ID for each network) | | payments | No | { registryAppId?: bigint; fluxOracleAppId?: bigint } — Waypoint registry / Flux oracle app IDs (default per network; algodClient is passed through for on-chain route reads) |

Lending domain (sdk.lending)

Read-only access to CompX lending markets. All methods work without a wallet.

| Method | Description | |--------|-------------| | getMarket(appId) | Comprehensive MarketData (APYs, TVL, utilization, rate model) | | getAPY(appId) | Current supply/borrow APYs (APYData) | | getLSTPrice(appId) | LST exchange rate (LSTPrice) | | getMarkets(appIds) | Multiple markets in parallel | | getAllMarkets() | All markets discovered on chain via the Master Repo registry, enriched with on-chain data | | getMarketList() | Basic market list discovered on chain via the Master Repo registry (MarketInfo[]) | | getOraclePrice(oracleAppId, assetId) | Single oracle price (OraclePrice) | | getOraclePrices(oracleAppId, assetIds) | Multiple oracle prices (OraclePriceMap) | | getAssetInfo(assetId) / getAssetsInfo(assetIds) | Asset metadata from Algorand | | getMarketLoanRecords(appId) | All active loan records in a market | | getAllDebtPositions(marketAppIds) | Debt positions with health metrics | | getAllDebtPositionsFromAllMarkets() | Debt positions across all markets | | getUserPosition(appId, address) | A user's position in one market | | getAllUserPositions(address) | Aggregated positions across all markets | | getUserPositionsForMarkets(address, appIds) | Aggregated positions across given markets | | getGlobalState(appId) | Raw market global state |

const market = await sdk.lending.getMarket(12345678);
console.log(`Supply APY: ${market.supplyApy.toFixed(2)}%`);
console.log(`Borrow APY: ${market.borrowApy.toFixed(2)}%`);

const positions = await sdk.lending.getAllUserPositions('USERADDRESS...');
console.log(`Active in ${positions.activeMarkets} markets`);

Calculation and state-decode helpers are also exported directly: utilNormBps, aprBpsKinked, currentAprBps, calculateLSTDue, calculateAssetDue, calculateLSTPrice, microToStandard, standardToMicro, getApplicationGlobalState, getBoxValue, decodeDepositRecord, decodeLoanRecord, decodeOraclePrice, createDepositBoxName, createLoanBoxName, createOraclePriceBoxName, getRegisteredContracts, getRegisteredAppIdsByType, getRegisteredLendingAppIds, getRegisteredStakingAppIds, DEFAULT_MASTER_REPO_APP_ID.

Building lending transactions

The SDK can build ready-to-sign, correctly grouped unsigned transactions for the core lending actions against ASA-base markets. The SDK never signs or submits: each builder returns unsigned algosdk.Transaction objects with the atomic group ID already assigned, plus signing instructions and metadata. App-call resources (boxes, foreign apps/assets) and inner-transaction fees are resolved up front (via simulate, no signer required), so the group is valid as-is once signed.

| Method | Group shape | |--------|-------------| | buildDepositTransactions({ appId, sender, amount }) | [optInLST?] → baseTransfer → depositASA | | buildWithdrawTransactions({ appId, sender, amount }) | [optInBase?] → lstTransfer → withdrawDeposit | | buildBorrowTransactions({ appId, sender, borrowAmount, collateralAmount, collateralTokenId }) | [optInBase?] → gas → collateralTransfer → borrow | | buildRepayTransactions({ appId, sender, amount }) | baseTransfer → repayLoanASA |

All amounts are in base units (micro units) as bigint | number. Each builder also accepts an optional appCallMaxFee (microAlgos, defaults to DEFAULT_APP_CALL_MAX_FEE = 250_000) and validityWindow (rounds). Needed asset opt-ins are detected and prepended automatically; metadata.optInsIncluded lists any added.

const bundle = await sdk.lending.buildDepositTransactions({
  appId: 12345678,
  sender: 'USERADDRESS...',
  amount: 1_000_000n, // base units of the base asset
});

// bundle.transactions: unsigned algosdk.Transaction[] with group ID assigned
// bundle.signers:      [{ address, transactionIndexes }] signing instructions
// bundle.metadata:     { action, appId, sender, baseTokenId, lstTokenId, optInsIncluded }

// Sign every transaction with the connected wallet, then submit the group:
const signed = await wallet.signTransactions(bundle.transactions);
await algodClient.sendRawTransaction(signed).do();

The standalone functions buildDepositTransactions, buildWithdrawTransactions, buildBorrowTransactions, and buildRepayTransactions (which take (algodClient, params)) are also exported. See src/examples/lending-build-transactions.ts.

Staking domain (sdk.staking)

Read-only access to CompX staking pools.

| Method | Description | |--------|-------------| | getPoolAppIds() | Discover all staking pool app IDs from the on-chain Master Repo registry | | getAllPools() | Discover and read StakingPoolState for every registered pool | | getPool(appId) | Decoded StakingPoolState (stake, rewards, timing, fees) | | getPools(appIds) | Multiple pools in parallel | | getStakerInfo(appId, address) | A single staker's record (StakerInfo) or null | | getPoolApr(appId, options) | Annualized APR percentage, or null if indeterminable | | getMasterRepoAppId() | Master Repo app ID used for on-chain pool discovery | | createStakerBoxName(address) | Builds the staker box name |

Pool discovery uses the same on-chain Master Repo registry as lending (defaulting to the known app ID per network); pass masterRepoAppId to override it.

// Discover and read every staking pool on chain
const pools = await sdk.staking.getAllPools();
const pool = await sdk.staking.getPool(23456789);

// USD-accurate APR for cross-asset pools
const apr = await sdk.staking.getPoolApr(23456789, {
  stakedAssetDecimals: 6,
  rewardAssetDecimals: 6,
  stakedAssetPriceUsd: 0.15,
  rewardAssetPriceUsd: 1.0,
});
console.log(apr === null ? 'APR n/a' : `${apr.toFixed(2)}% APR`);

The pure APR helper calculateStakingApr and formatAmount / SECONDS_PER_YEAR are exported for off-chain use.

Payments domain (sdk.payments)

On-chain discovery and reads for Waypoint payment routes (send/request tokens over time), plus portable fee and vesting calculations.

Payments uses a dedicated Waypoint registry (separate from the lending/staking Master Repo). Each route is its own deployed app; the registry's routes BoxMap indexes them by route app ID. The registry app ID defaults per network (mainnet 3253603509); override via payments.registryAppId.

| Method | Description | |--------|-------------| | getRouteAppIds() | Discover all route app IDs from the on-chain Waypoint registry | | getRoute(routeAppId, nowTimestamp?) | Decoded, claim-aware RouteViewModel (linear or invoice) or null | | getAllRoutes(nowTimestamp?) | Discover and read every registered route | | getNominatedAssetId() | Nominated platform asset ID from the registry | | getUserFluxTier(address) | A user's Flux fee-discount tier (0 when disabled) | | estimateRouteFeeForUser(amount, tokenId, address) | Fee using on-chain tier + nominated asset | | feeBps(isNominatedAsset, tier) | Fee in basis points for an asset/tier | | estimateRouteFee(amount, tokenId, tier, nominatedAssetId) | Fee for a deposit amount (pure) | | calculateClaimable(route, nowTimestamp?) | Currently claimable amount for a route (pure) | | parseAmount(value, decimals) | Parse a decimal string into base units (pure) |

// Discover and read every route on chain
const routes = await sdk.payments.getAllRoutes();

// 25 bps for the nominated asset at tier 0 (pure calculation)
const fee = sdk.payments.estimateRouteFee(1_000_000n, 31566704n, 0, 31566704n);

On-chain methods require an algodClient (passed through from CompXSDK). The pure calculation helpers (tierToBps, calculateFee, parseDecimalToUnits, calculateClaimableAmount, RouteKind, InvoiceRouteStatus, DEFAULT_WAYPOINT_REGISTRY_APP_ID, DEFAULT_FLUX_ORACLE_APP_ID, fee-tier tables) are exported directly.

Building payments transactions

The SDK can build ready-to-sign, correctly grouped unsigned transactions for Waypoint payment routes (linear send, invoice request, accept/decline, claim, and manual registry re-index). The SDK never signs or submits: each builder returns unsigned algosdk.Transaction objects with the atomic group ID already assigned, plus signing instructions and metadata. App-call resources and inner-transaction fees are resolved up front (via simulate, no signer required).

Route creation is multi-step because the route app must confirm before its routeAppId is known. Use the typed plan helpers (buildCreateLinearRoutePlan, buildCreateInvoiceRoutePlan) or call each step builder individually.

| Method | Group shape | Signer | |--------|-------------|--------| | buildCreateLinearApplicationTransactions | [createApplication] (standalone) | depositor | | buildInitLinearRouteTransactions | [mbrPayment → initApp] | depositor | | buildCreateLinearRouteTransactions | [tokenTransfer → createRoute] | depositor | | buildCreateInvoiceApplicationTransactions | [createApplication] (standalone) | requester | | buildInitInvoiceRouteTransactions | [mbrPayment → initApp] | requester | | buildCreateInvoiceRouteTransactions | [createRoute] | requester | | buildAcceptInvoiceRouteTransactions | [tokenTransfer → acceptRoute] | payer | | buildDeclineInvoiceRouteTransactions | [declineRoute] | payer | | buildClaimRouteTransactions | [optIn? → claim] | beneficiary | | buildRegisterRouteTransactions | [registerRoute] on registry | any account (not admin-gated) |

Registry indexing is automatic via inner calls in createRoute (linear) and acceptRoute (invoice). buildRegisterRouteTransactions is only needed to re-index routes missing from the registry.

Claim (single group):

const bundle = await sdk.payments.buildClaimRouteTransactions({
  routeAppId: 123456789n,
  beneficiary: 'BENEFICIARY...',
  routeKind: 'linear', // optional; auto-detected when omitted
});

const signed = await wallet.signTransactions(bundle.transactions);
await algodClient.sendRawTransaction(signed).do();

Create linear route (multi-step):

import { extractCreatedAppId } from '@compx/sdk';

const plan = await sdk.payments.buildCreateLinearRoutePlan({
  sender: 'DEPOSITOR...',
  beneficiary: 'BENEFICIARY...',
  tokenId: 31_566_704n,
  depositAmount: 1_000_000n,
  payoutAmount: 100_000n,
  startTimestamp: BigInt(Math.floor(Date.now() / 1000)),
  periodSeconds: 86_400n,
  maxPeriods: 10n,
});

// Step 1: deploy route app
const signed1 = await wallet.signTransactions(plan.createApplication.transactions);
const { txid } = await algodClient.sendRawTransaction(signed1).do();
const confirmed = await algosdk.waitForConfirmation(algodClient, txid, 4);
const routeAppId = extractCreatedAppId(confirmed);

// Step 2: fund MBR + init
const initBundle = await plan.initApp(routeAppId);
const signed2 = await wallet.signTransactions(initBundle.transactions);
await algodClient.sendRawTransaction(signed2).do();

// Step 3: deposit + create route (registers in registry via inner call)
const routeBundle = await plan.createRoute(routeAppId);
const signed3 = await wallet.signTransactions(routeBundle.transactions);
await algodClient.sendRawTransaction(signed3).do();

Standalone builder functions (which take (algodClient, params)) are also exported. See src/examples/payments-build-transactions.ts.

clAMM domain (sdk.clamm)

Not yet available. The clAMM contracts exist on-chain, but a stable SDK surface for manager-routed transactions is still being finalized. CLAMM_STATUS is 'pending', and constructing ClammClient throws. Track docs/clamm-contract-reference.md for progress.

Features

  • Multi-domain: staking, lending, payments (clAMM coming soon)
  • Read- and calculation-focused: no wallet required
  • Bring your own algosdk clients (custom nodes, tokens, networks)
  • Fully typed with detailed TypeScript definitions
  • Ships CJS, ESM, and type declarations

Development

pnpm install        # Install dependencies
pnpm run build      # Build the SDK (CJS + ESM + d.ts)
pnpm run dev        # Watch mode
pnpm run test       # Run unit tests (mocked, no network)
pnpm run typecheck  # Type checking
pnpm run lint       # Lint

pnpm run test:integration  # Live tests (real funds; requires .env.test)

Live integration tests for the transaction builders submit real transactions and are gated behind .env.test credentials. They are skipped by default. See TESTING.md for setup and safety notes.

License

MIT