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

@avalabs/unified-asset-transfer

v0.1.0

Published

<p align="center"> <a href="https://subnets.avax.network/"> <picture> <img alt="Avalanche Logo" src="https://images.ctfassets.net/gcj8jwzm6086/Gse8dqDEnJtT87RsbbEf4/1609daeb09e9db4a6617d44623028356/Avalanche_Horizontal_White.svg" width="auto" heig

Readme

What is this?

@avalabs/unified-asset-transfer provides a single, ergonomic interface to move assets within and across chains. It aggregates multiple services (bridges, DEX aggregators, etc.), streams time-sensitive quotes, executes transfers with your custom signers, and tracks progress until completion.

Current integrations include:

  • Avalanche EVM transfer service (Avalanche ↔ Ethereum flows, native and ERC-20 flows where supported)
  • Lombard BTC ↔ BTC.b bridging services
  • Markr (swaps and cross-chain swaps via Markr Orchestrator)
  • Wrap/unwrap service for native ↔ wrapped native assets on supported EVM chains

Installation

This package is ESM-first. Install along with peer dependencies you use in your app:

# with pnpm
pnpm add @avalabs/unified-asset-transfer @solana/kit viem zod

# with npm
npm install @avalabs/unified-asset-transfer @solana/kit viem zod

# with yarn
yarn add @avalabs/unified-asset-transfer @solana/kit viem zod

Quickstart

Create a TransferManager by specifying an environment and enabling one or more services via initializers. Provide signers that match the services you enable.

import {
  createTransferManager,
  Environment,
  ServiceType,
  AVALANCHE_MAINNET_CHAIN,
  ETHEREUM_MAINNET_CHAIN,
  TokenType,
  type EvmSigner,
  type Asset,
} from '@avalabs/unified-asset-transfer';
import { parseUnits } from 'viem';

// Minimal EVM signer. You can ignore the provided `dispatch` and
// relay with your wallet directly, returning the tx hash.
const evmSigner: EvmSigner = {
  sign: async (tx, _dispatch, step) => {
    // Example using an injected EIP-1193 provider
    const hash: `0x${string}` = await (window as any).ethereum.request({
      method: 'eth_sendTransaction',
      params: [
        {
          from: tx.from,
          to: tx.to ?? undefined,
          data: tx.data ?? undefined,
          value: tx.value ? `0x${tx.value.toString(16)}` : undefined,
          maxFeePerGas: tx.maxFeePerGas ? `0x${tx.maxFeePerGas.toString(16)}` : undefined,
          maxPriorityFeePerGas: tx.maxPriorityFeePerGas ? `0x${tx.maxPriorityFeePerGas.toString(16)}` : undefined,
        },
      ],
    });

    return hash;
  },
};

// Enable services you want to use
const transferManager = await createTransferManager({
  environment: Environment.PROD,
  serviceInitializers: [
    { type: ServiceType.AVALANCHE_EVM, evmSigner },
    {
      type: ServiceType.MARKR,
      evmSigner,
      markrApiUrl: 'https://orchestrator.markr.io', // Optional, defaults to use proxy endpoint.
      markrApiToken: process.env.MARKR_API_TOKEN, // Optional, not needed if using default proxy url.
      markrAppId: process.env.MARKR_APP_ID!, // Required.
    },
  ],
});

// Build a quoting intent
const sourceChain = ETHEREUM_MAINNET_CHAIN;
const targetChain = AVALANCHE_MAINNET_CHAIN;

const sourceAsset: Asset = sourceChain.networkToken; // e.g., ETH
const targetAsset: Asset = {
  name: 'Wrapped Ether',
  symbol: 'WETH.e',
  decimals: 18,
  type: TokenType.ERC20,
  address: '0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab',
};

const from = '0xYourAddress';
const to = from;

const quoter = transferManager.getQuoter({
  amount: parseUnits('0.05', sourceAsset.decimals),
  fromAddress: from,
  slippageBps: 100, // 1%
  sourceAsset,
  sourceChain,
  targetAsset,
  targetChain,
  toAddress: to,
});

// Subscribe for streaming quotes. Subscription starts immediately.
const unsubscribe = quoter.subscribe((event, payload) => {
  if (event === 'quote') {
    console.log('New quote', payload.bestQuote);
  }
  if (event === 'error') {
    console.error('Quote error', payload);
  }
  if (event === 'done') {
    console.log('Quote stream ended', payload.reason);
  }
});

// ...later, stop streaming and pick the latest best quote
// This just simulates waiting for the user to start a "swap" after seeing quotes
// and selecting one to execute.
await wait(5000);
unsubscribe();

// This is a convenience method to get the latest quotes after streaming has stopped, but you can also maintain the latest quote in your own state from the subscription handler, which is recommended.
const [best, allQuotes] = quoter.getQuotes();
if (!best) throw new Error('No quotes available');

// Estimate the native fee for the transfer
const estimatedNativeFee = await transferManager.estimateNativeFee(best, { feeUnitsMarginBps: 2000 });
console.log('Estimated Native Fee (wei):', estimatedNativeFee.totalFee.toString());

// Execute the transfer
const transfer = await transferManager.transferAsset({
  quote: best,
  gasSettings: {
    estimateGasMarginBps: 1500, // Adds 15% margin to the gas estimate to help prevent gas failures.
    // maxFeePerGas, maxPriorityFeePerGas can be provided for EIP-1559 wallets
  },
  onStepChange: (step) => {
    console.log('Signature step', step);
  },
});

// Track until finalized (optional)
const { cancel, result } = transferManager.trackTransfer({
  transfer,
  updateListener: (updated) => console.log('Transfer update', updated),
});

// await cancel(); // to stop tracking early
const finalized = await result;
console.log('Finalized transfer', finalized);

API Overview

createTransferManager(options)

Creates and returns a TransferManager that aggregates the services you enable.

type CreateTransferManagerOptions = {
  environment: Environment; // dev | production | test
  serviceInitializers: readonly [ServiceInitializer, ...(readonly ServiceInitializer[])];
  fetch?: Fetch;
};

TransferManager

  • id: string: Unique identifier for the transfer manager instance.
  • status(): TransferManagerStatus: Returns initialization/status details per requested service.
  • getAssetBridgeMap({ sourceAsset, sourceChainId }): Promise<AssetBridgeMap | null>: Given a source asset and chain, get possible bridge target assets per chain.
  • getSupportedChains(): Promise<ReadonlyMap<Caip2ChainId, ReadonlySet<Caip2ChainId>>>: Supported source → destination chain pairs across initialized services.
  • getQuoter(props: QuoterProps, options?: QuoterOptions): QuoterInterface: Create a streaming quote aggregator.
  • estimateNativeFee(quote, options?): Promise<NativeFeeEstimate>: Service-aware native fee estimate.
  • getMinimumTransferAmount(props): Promise<{ [key in ServiceType]?: bigint } | null>: Minimum amount per service for a given transfer intent.
  • transferAsset({ quote, gasSettings?, onStepChange? }): Promise<Transfer>: Execute the selected quote.
  • trackTransfer({ transfer, updateListener }): { cancel, result }: Track a transfer to completion.

Quoter

  • subscribe(handler): Starts streaming on first subscriber; returns unsubscribe.
  • getQuotes(): [bestQuote: Quote | null, allQuotes: readonly Quote[]]: Snapshot of current active quotes.

Quoter behavior

The Quoter aggregates all eligible initialized services for a single transfer intent and emits a unified stream of events:

  • quote: emitted whenever a service returns a quote; payload includes bestQuote, the latest quote, and current active quotes.
  • error: emitted when a service attempt errors; this is non-terminal by itself.
  • done: terminal event with one of these reasons:
    • unsubscribed: all subscribers removed.
    • no-eligible-services: no initialized service can serve the requested pair.
    • no-quotes: all eligible services have completed and no quote was produced.

Lifecycle notes:

  • Streaming starts lazily on first subscription.
  • Quotes are maintained as active (non-expired) quotes and internally re-ranked as updates arrive.
  • Services with active quotes are refreshed before quote expiry.
  • Services that finish without quotes are only retried after at least one quote has already been observed during the current session.
  • If all eligible services finish during first pass with no quotes, quoter completes immediately with done: no-quotes.

Types and Constants

Key exports are available from the package entry:

  • Chains: AVALANCHE_MAINNET_CHAIN, AVALANCHE_FUJI_CHAIN, ETHEREUM_MAINNET_CHAIN, ETHEREUM_SEPOLIA_CHAIN, BITCOIN_MAINNET_CHAIN, BITCOIN_TESTNET_CHAIN, SOLANA_MAINNET_CHAIN, SOLANA_DEVNET_CHAIN.
  • Enums: Environment, ServiceType, TokenType.
  • Types: Asset, Chain, Quote, Transfer, EvmSigner, BtcSigner, ChainAssetMap, QuoterProps.
  • Errors: SdkError, InvalidParamsError, ServiceInitializationError, ServiceUnavailableError, TimeoutError, helpers like isSdkError(...).
  • Utilities: CAIP helpers from utils/caip.

Assets and chains use CAIP-2 identifiers internally (for example, eip155:43114 for Avalanche C-Chain). See ChainAssetMap for the shape returned by getAssets().

Notes on Signers

  • The EVM signer interface gives you full control over signing and broadcasting. You may:
    • Submit via your wallet (ignore dispatch) and return the tx hash, or
    • Use the provided dispatch(serializedTx) to broadcast a pre-signed transaction.
  • Some services require fromAddress and toAddress to be identical (e.g., Avalanche EVM service). The SDK enforces these rules per service.

Supported Services

  • ServiceType.AVALANCHE_EVM
  • ServiceType.WRAP_UNWRAP
  • ServiceType.LOMBARD_BTC_TO_BTCB
  • ServiceType.LOMBARD_BTCB_TO_BTC
  • ServiceType.MARKR

Environment Support by Service

createTransferManager({ environment, serviceInitializers }) evaluates each configured service against the selected Environment.

| ServiceType | Environment.DEV (dev) | Environment.TEST (test) | Environment.PROD (production) | Notes | | --------------------------------- | ------------------------- | --------------------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------- | | ServiceType.AVALANCHE_EVM | ✅ | ✅ | ✅ | Uses Warden config for the selected environment. | | ServiceType.WRAP_UNWRAP | ✅ | ✅ | ✅ | test uses testnet chain configs; dev and production currently use mainnet chain configs. | | ServiceType.LOMBARD_BTC_TO_BTCB | ✅ | ✅ | ✅ | Environment maps to Lombard envs (devEnv.dev, testEnv.ibc, productionEnv.prod). | | ServiceType.LOMBARD_BTCB_TO_BTC | ✅ | ✅ | ✅ | Environment maps to Lombard envs (devEnv.dev, testEnv.ibc, productionEnv.prod). | | ServiceType.MARKR | ❌ | ❌ | ✅ | Production-only. In non-production, status is unsupported-environment. |

You can inspect initialization outcomes with transferManager.status() to see per-service states (initialized, error, or unsupported-environment).

License

Licensed under the Limited Ecosystem License. See the LICENSE file in this package for details.