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

@tribridge/triverify

v0.2.0

Published

A zero-dependency, type-safe TypeScript SDK for cross-chain crypto **address validation, chain detection, on-chain verification, domain resolution, and batch processing**.

Readme

@tribridge/triverify

A zero-dependency, type-safe TypeScript SDK for cross-chain crypto address validation, chain detection, on-chain verification, domain resolution, and batch processing.

One SDK. Every major chain. Validate any address before it ever touches your app.


Features

  • Zero external dependencies — core validation is pure TypeScript, so it ships tiny and never bloats your bundle.
  • Multi-chain format validation — strict per-chain rules (length, charset, prefix, EIP-55 checksum where applicable).
  • Confidence-based auto-detection — detect() scores every supported chain and reports the best match, flagging ambiguity when two chains share a format.
  • Real on-chain verification — verifyOnChain() checks whether an address is actually present / active on the network using free public RPC endpoints (with automatic fallback).
  • Address-type detection — distinguish wallets (EOAs) from contracts / programs on-chain.
  • Domain resolution — resolve vitalik.eth, bonfida.sol, mysten.sui, name.apt, name.ton, name.tron, and Unstoppable .crypto domains to raw addresses.
  • Batch validation — validate, detect, normalize, dedupe, and summarize thousands of addresses in parallel.
  • First-class TypeScript — fully typed inputs and return values, tree-shakeable ESM + CJS builds.

Supported chains

| Chain | Format notes | | ---------- | ----------------------------------------------------------------- | | Ethereum | 0x + 40 hex (EIP-55 mixed-case checksum aware) | | Polygon | EVM, 0x + 20 bytes (shares Ethereum format) | | Bitcoin | Legacy (1…), P2SH (3…), SegWit / Bech32 (bc1…) | | Solana | Base58, 32–44 chars | | Tron | Base58, T… prefix, 34 chars | | Sui | 0x + 32 bytes (64 hex) | | Aptos | 0x + up to 32 bytes (leading zeros may be omitted) | | TON | Raw (-1: / 0:) and user-friendly base64url |

Sui vs Aptos: both use an identical 0x + 32-byte address space, so a 66-char 0x address is format-ambiguous. detect() returns the address as the most likely chain and attaches an ambiguityNote telling you to verify on-chain. A 42-char 0x address is unambiguously EVM/Polygon and is never reported as Aptos.


Installation

npm install @tribridge/triverify
# or
pnpm add @tribridge/triverify
yarn add @tribridge/triverify

Quick start

import { validate, detect, verifyOnChain, Chain } from '@tribridge/triverify';

// 1. Validate a single address against a known chain
validate('0x742d35Cc6634C0532925a3b844Bc454e4438f44e', Chain.Ethereum);
// → { isValid: true, chain: 'ethereum', confidence: 1, reason: '...' }

// 2. Auto-detect the chain from the address alone
detect('HN7cABqL36GNBbpR9S99S46ptP99P5y7aZ');
// → top match: { chain: 'solana', score: 100 }

// 3. Confirm it is live on-chain
await verifyOnChain('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', Chain.Ethereum);
// → { exists: true, active: true, type: 'wallet', balance: '...' }

API Reference

validate(address, chain)

Validates a single address against a specific chain.

function validate(address: string, chain: Chain): ValidationResult;

Returns ValidationResult:

interface ValidationResult {
  isValid: boolean;
  chain: Chain | null;
  confidence: number;      // 0–1
  reason?: string;         // human-readable explanation
}

detect(address)

Detects which chain(s) an address most likely belongs to using confidence scoring (character set + prefix + length + format/checksum, each worth up to 25 points).

function detect(address: string): DetectResult;

Returns DetectResult:

interface DetectResult {
  address: string;
  results: ConfidenceResult[];     // all chains that matched, sorted by score desc
  isAmbiguous: boolean;            // true when the top two chains are within 10 points
  topMatch: ConfidenceResult | null;
  ambiguityNote?: string | null;  // set when the match collides with an identical-format chain (e.g. Sui/Aptos)
}

interface ConfidenceResult {
  chain: Chain;
  score: number;                  // 0–100
  reasons: {
    prefixMatch: boolean;
    lengthMatch: boolean;
    checksumValid: boolean;
    characterSetMatch: boolean;
  };
}

Only chains that score as genuinely valid (≥ 60) are returned, so you never see misleading low-confidence noise.

import { detect } from '@tribridge/triverify';

const { results, ambiguityNote } = detect('0x1e2e...daa');
// results[0] → { chain: 'sui', score: 100, reasons: { ...: true } }
// ambiguityNote → "This address also matches the Aptos format …"

verifyOnChain(address, chain, options?)

Goes beyond format checks and confirms whether the address is present / active on the blockchain.

async function verifyOnChain(
  address: string,
  chain: Chain,
  options?: VerifyOptions
): Promise<VerifyResult>;

VerifyOptions:

interface VerifyOptions {
  rpcUrl?: string;   // override the public endpoint
  apiKey?: string;   // e.g. Trongrid / Toncenter API key
  timeoutMs?: number; // per-request timeout (default 8000)
}

Returns VerifyResult:

interface VerifyResult {
  address: string;
  chain: Chain;
  exists: boolean;       // account present on-chain
  active: boolean;       // has balance / nonce / txns / code
  type: 'wallet' | 'contract' | 'unknown';
  balance?: string;      // native balance (string, in base units)
  transactionCount?: number;
  source: string;        // endpoint that was queried
  supported: boolean;
  error?: string;        // present when the check could not be completed
}

Endpoints used (no API key required for the defaults; Solana and Sui try multiple public nodes with automatic fallback):

| Chain | Default endpoint | | -------- | ------------------------------------------------------------ | | Ethereum | https://ethereum-rpc.publicnode.com | | Polygon | https://polygon-bor-rpc.publicnode.com | | Bitcoin | https://mempool.space/api | | Solana | https://solana-rpc.publicnode.com (+ onfinality fallback) | | Tron | https://api.trongrid.io | | Sui | https://graphql.mainnet.sui.io/graphql (+ fallbacks) | | Aptos | https://fullnode.mainnet.aptoslabs.com/v1 | | TON | https://toncenter.com/api/v2 |

import { verifyOnChain, Chain } from '@tribridge/triverify';

const res = await verifyOnChain('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', Chain.Ethereum);
console.log(res.exists, res.active, res.type, res.balance);

getAddressType(address, chain, rpcUrl)

Classifies an on-chain address as a wallet (EOA) or contract / program.

async function getAddressType(
  address: string,
  chain: Chain,
  rpcUrl: string
): Promise<AddressTypeResult>;
interface AddressTypeResult {
  type: 'wallet' | 'contract' | 'unknown';
  supported: boolean;
  reason?: string;
  rawResponse?: any;
}

resolveAddress(input, options?)

Resolves a human-readable domain to a raw address across supported naming services.

async function resolveAddress(
  input: string,
  options?: ResolutionOptions
): Promise<ResolutionResult>;
interface ResolutionOptions {
  rpcUrl?: string;   // override the default RPC / gateway per service
  apiKey?: string;   // for Unstoppable Domains
}

interface ResolutionResult {
  address: string | null;  // resolved raw address (or the input if not a domain)
  wasResolved: boolean;
  domain: string | null;
  error?: string;
}

Supported TLDs: .eth (ENS), .sol (SNS), .sui (SuiNS), .apt (ANS), .ton (TON DNS), .tron (Tron), .crypto (Unstoppable Domains).

import { resolveAddress } from '@tribridge/triverify';

const { address, wasResolved } = await resolveAddress('vitalik.eth');
// → { address: '0xd8dA...6045', wasResolved: true }

validateBatch(addresses, options?)

Validates a large list of addresses in parallel, with detection, normalization, dedupe, and ambiguity reporting.

async function validateBatch(
  addresses: string[],
  options?: BatchOptions
): Promise<BatchResult>;
interface BatchOptions {
  chain?: Chain;        // validate against one chain only
  detectAll?: boolean;  // auto-detect chain per address
  includeDuplicates?: boolean;
  normalize?: boolean;  // lowercase EVM/Sui/Aptos, leave Base58/Base64 as-is
}

interface BatchResult {
  valid:   Array<{ address: string; chain: Chain; confidence: number; normalized?: string }>;
  invalid: Array<{ address: string; reason: string }>;
  duplicates: string[];
  ambiguous: Array<{ address: string; matches: ConfidenceResult[] }>;
  summary: { total: number; validCount: number; invalidCount: number; duplicateCount: number; ambiguousCount: number };
}
import { validateBatch } from '@tribridge/triverify';

const { valid, invalid, duplicates, ambiguous, summary } = await validateBatch(
  ['0x742d...', 'HN7cAB...', 'bc1qxy...'],
  { detectAll: true, normalize: true }
);
console.log(summary);

Notes & caveats

  • Format ≠ ownership. Validation only proves an address is well-formed. Use verifyOnChain() to confirm it exists / is active.
  • Sui / Aptos share an identical address format; the SDK cannot tell them apart without an on-chain lookup. The ambiguityNote field is your cue to verify on-chain.
  • Public RPC endpoints are rate-limited and best-effort. For production, pass your own rpcUrl (and apiKey where required) via VerifyOptions.

License

MIT