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

sns-sdk

v2.0.2

Published

JavaScript/TypeScript SDK for Sonic Name Service (SNS) V2 - Easy integration for dApps with bulk operations, contenthash, and enhanced features

Downloads

64

Readme

Sonic Name Service (SNS) SDK V2

JavaScript/TypeScript SDK for easy integration with Sonic Name Service - the decentralized domain name system for the Sonic blockchain.

🎉 Version 2.0 is here! This major update brings bulk operations, ENS-compatible contenthash, custom NFT images, and enhanced text record management.

Features

  • 🚀 Simple Integration - Easy-to-use API for domain resolution and management
  • 🔄 Unified Interface - Single point of access for all SNS functionality
  • Performance Optimized - Built-in caching and retry mechanisms
  • 🛡️ Type Safe - Full TypeScript support with comprehensive type definitions
  • 🔗 Batch Operations - Efficiently resolve multiple domains or addresses
  • 📝 Record Management - Support for address, content, and text records
  • 🎯 Error Handling - Detailed error types and clear error messages

🆕 What's New in V2

  • 📦 Bulk Operations - Register or renew up to 20 domains in a single transaction
  • 🌐 ENS-Compatible Contenthash - Full IPFS/Swarm support following ENSIP-7 standard
  • 🎨 Custom NFT Images - Set custom avatars/images for domain NFTs
  • Batch Text Records - Set multiple text records at once for gas efficiency
  • 👤 Primary Names - Enhanced reverse resolution with primary name system
  • 📱 Social Records Helper - Convenient methods for Twitter, GitHub, Discord, Telegram
  • 🔄 Upgradeable Contracts - Built on OpenZeppelin UUPS proxy pattern
  • 💎 ERC-4906 Metadata - Real-time NFT marketplace updates
  • 👑 ERC-2981 Royalties - Built-in royalty support for secondary sales

Installation

npm install sns-sdk ethers@^6.0.0
yarn add sns-sdk ethers@^6.0.0

Note: This SDK requires ethers.js v6. If you're using ethers v5, please upgrade to v6.

Quick Start

import { SNS } from 'sns-sdk';
import { JsonRpcProvider } from 'ethers';

// Initialize the SDK
const provider = new JsonRpcProvider('https://rpc.soniclabs.com');
const sns = new SNS({ provider });

// Resolve a domain to an address
const address = await sns.resolve('krownlab.s');
console.log(address); // 0xc957215773a8b86c8d8bab235451e467caaf944c

// Reverse resolve an address to a domain
const domain = await sns.reverseResolve('0xc957215773a8b86c8d8bab235451e467caaf944c');
console.log(domain); // krownlab.s

// Check domain availability
const available = await sns.isAvailable('alice.s');
console.log(available); // true/false

// Get registration price
const price = await sns.getPrice('alice.s', 1); // 1 year
console.log(price.priceInEther); // "5.0"

Configuration

import { SNS } from 'sns-sdk';

const sns = new SNS({
  provider: provider,                    // Required: ethers.js provider
  registryAddress: '0x...',              // Optional: custom registry address
  registrarAddress: '0x...',             // Optional: custom registrar address  
  resolverAddress: '0x...',              // Optional: custom resolver address
  cacheEnabled: true,                    // Optional: enable caching (default: true)
  cacheTTL: 5 * 60 * 1000,               // Optional: cache TTL in ms (default: 5 min)
  retryAttempts: 3,                      // Optional: retry attempts (default: 3)
  retryDelay: 1000                       // Optional: retry delay in ms (default: 1s)
});

API Reference

Resolution Methods

resolve(domain: string): Promise<string>

Resolve a domain name to an Ethereum address.

const address = await sns.resolve('krownlab.s');

reverseResolve(address: string): Promise<string>

Reverse resolve an address to a domain name.

const domain = await sns.reverseResolve('0xc957215773a8b86c8d8bab235451e467caaf944c');

getContent(domain: string): Promise<string>

Get content hash for a domain.

const contentHash = await sns.getContent('krownlab.s');

getText(domain: string, key: string): Promise<string>

Get text record for a domain.

const github = await sns.getText('krownlab.s', 'github');
const x = await sns.getText('krownlab.s', 'x');

Batch Operations

resolveBatch(domains: string[]): Promise<BatchResolutionResult>

Resolve multiple domains in batches.

const result = await sns.resolveBatch(['krownlab.s', 'alice.s', 'bob.s']);
console.log(result.successful); // Successfully resolved domains
console.log(result.failed);     // Failed resolutions with errors

reverseResolveBatch(addresses: string[]): Promise<BatchReverseResolutionResult>

Reverse resolve multiple addresses in batches.

const result = await sns.reverseResolveBatch([
  '0xc957215773a8b86c8d8bab235451e467caaf944c',
  '0x123...',
  '0x456...'
]);

V2: Bulk Operations

registerBulk(domains: Array<{ name: string; years: number }>, signer: Signer): Promise<string>

Register multiple domains in a single transaction (up to 20 domains).

const txHash = await sns.registerBulk([
  { name: 'domain1', years: 1 },
  { name: 'domain2', years: 2 },
  { name: 'domain3', years: 1 }
], wallet);

renewBulk(renewals: Array<{ domain: string; years: number }>, signer: Signer): Promise<string>

Renew multiple domains in a single transaction.

const txHash = await sns.renewBulk([
  { domain: 'mydomain1.s', years: 1 },
  { domain: 'mydomain2.s', years: 2 }
], wallet);

calculateBulkPrice(domains: Array<{ name: string; years: number }>): Promise<BulkPriceResult>

Calculate total price for bulk registration.

const result = await sns.calculateBulkPrice([
  { name: 'domain1', years: 1 },
  { name: 'domain2', years: 2 }
]);
console.log(result.totalPriceInEther); // "10.0"
console.log(result.breakdown);          // Per-domain price breakdown

V2: Contenthash (IPFS/Swarm)

getContenthash(domain: string): Promise<string>

Get ENS-compatible contenthash for a domain.

const contenthash = await sns.getContenthash('mydomain.s');
// Returns bytes in ENSIP-7 format

setContenthash(domain: string, hash: string, signer: Signer): Promise<string>

Set contenthash for a domain (supports IPFS/Swarm).

// IPFS example
const txHash = await sns.setContenthash('mydomain.s', '0xe3010170...', wallet);

V2: Enhanced Text Records

getTexts(domain: string, keys: string[]): Promise<Record<string, string>>

Get multiple text records at once.

const records = await sns.getTexts('mydomain.s', [
  'email', 'url', 'avatar', 'description'
]);
console.log(records.email); // "[email protected]"

setTextBatch(domain: string, records: Record<string, string>, signer: Signer): Promise<string>

Set multiple text records in a single transaction.

const txHash = await sns.setTextBatch('mydomain.s', {
  'email': '[email protected]',
  'com.twitter': '@alice',
  'com.github': 'alice',
  'url': 'https://alice.com'
}, wallet);

getSocials(domain: string): Promise<SocialRecords>

Get social media records for a domain.

const socials = await sns.getSocials('mydomain.s');
console.log(socials.twitter);  // Twitter handle
console.log(socials.github);   // GitHub username
console.log(socials.discord);  // Discord username
console.log(socials.telegram); // Telegram username

V2: Primary Names

setPrimaryName(domain: string, signer: Signer): Promise<string>

Set a domain as your primary name (replaces reverse records).

const txHash = await sns.setPrimaryName('mydomain.s', wallet);

clearPrimaryName(signer: Signer): Promise<string>

Clear your primary name.

const txHash = await sns.clearPrimaryName(wallet);

getPrimaryName(address: string): Promise<string>

Get the primary name for an address.

const primaryName = await sns.getPrimaryName('0x742d35Cc6aF66C59D32365bb44bB3eaA6b8F7e15');
console.log(primaryName); // "alice.s"

V2: Custom NFT Images

getCustomImage(domain: string): Promise<string>

Get custom image URI for a domain.

const imageURI = await sns.getCustomImage('mydomain.s');

setCustomImage(domain: string, imageURI: string, signer: Signer): Promise<string>

Set a custom image for your domain NFT.

// IPFS image
const txHash = await sns.setCustomImage(
  'mydomain.s',
  'ipfs://QmX...',
  wallet
);

// HTTP image
const txHash = await sns.setCustomImage(
  'mydomain.s',
  'https://example.com/my-avatar.png',
  wallet
);

clearCustomImage(domain: string, signer: Signer): Promise<string>

Clear custom image and revert to default SVG.

const txHash = await sns.clearCustomImage('mydomain.s', wallet);

Domain Management

isAvailable(domain: string): Promise<boolean>

Check if a domain is available for registration.

const available = await sns.isAvailable('newdomain.s');

getPrice(domain: string, years: number): Promise<PriceResult>

Get registration price for a domain.

const price = await sns.getPrice('newdomain.s', 2); // 2 years
console.log(price.priceInEther);    // Price in S
console.log(price.discount);        // Discount percentage
console.log(price.discountAmount);  // Discount amount in wei

register(domain: string, years: number, signer: Signer): Promise<string>

Register a new domain.

import { Wallet } from 'ethers';

const wallet = new Wallet('your-private-key', provider);
const txHash = await sns.register('newdomain.s', 1, wallet);
console.log(`Registration transaction: ${txHash}`);

registerAndConfigure(domain: string, years: number, resolverAddress: string, setPrimary: boolean, signer: Signer): Promise<string> 🆕

Register a domain and fully configure it in a single transaction. This is a gas-efficient convenience function that combines multiple operations:

  • Register the domain
  • Set the default resolver
  • Set the resolver address
  • Optionally set as primary name
import { Wallet } from 'ethers';

const wallet = new Wallet('your-private-key', provider);

// Register and configure in one transaction
const txHash = await sns.registerAndConfigure(
  'mydomain.s',          // domain name
  1,                     // years
  wallet.address,        // address to resolve to
  true,                  // set as primary name
  wallet
);

console.log(`Domain registered and configured: ${txHash}`);
// After this transaction:
// - Domain is registered for 1 year
// - Resolver is set
// - Domain resolves to wallet.address
// - Domain is set as primary name for wallet.address

renew(domain: string, years: number, signer: Signer): Promise<string>

Renew an existing domain.

const txHash = await sns.renew('mydomain.s', 1, wallet);

Record Management

setAddress(domain: string, address: string, signer: Signer): Promise<string>

Set the address record for a domain.

const txHash = await sns.setAddress(
  'mydomain.s', 
  '0x742d35Cc6aF66C59D32365bb44bB3eaA6b8F7e15',
  wallet
);

setText(domain: string, key: string, value: string, signer: Signer): Promise<string>

Set a text record for a domain.

// Set email
await sns.setText('mydomain.s', 'email', '[email protected]', wallet);

// Set social media
await sns.setText('mydomain.s', 'x', 'alice_crypto', wallet);
await sns.setText('mydomain.s', 'github', 'alice', wallet);

setContent(domain: string, content: string, signer: Signer): Promise<string>

Set content hash for a domain.

const txHash = await sns.setContent('mydomain.s', 'ipfs://Qm...', wallet);

Utility Methods

getDomainInfo(domain: string): Promise<DomainRecord>

Get comprehensive information about a domain.

const info = await sns.getDomainInfo('krownlab.s');
console.log(info.owner);      // Domain owner address
console.log(info.expiryTime); // Expiry timestamp
console.log(info.expired);    // Whether domain is expired
console.log(info.address);    // Resolved address

validateDomain(domain: string): ValidationResult

Validate a domain name according to SNS rules.

const validation = sns.validateDomain('my-domain');
console.log(validation.valid);  // true/false
console.log(validation.errors); // Array of error messages

Error Handling

The SDK provides detailed error types for better error handling:

import { 
  SNS, 
  DomainNotFoundError, 
  DomainExpiredError,
  ValidationError,
  NetworkError 
} from 'sns-sdk';

try {
  const address = await sns.resolve('nonexistent.s');
} catch (error) {
  if (error instanceof DomainNotFoundError) {
    console.log('Domain not found');
  } else if (error instanceof DomainExpiredError) {
    console.log('Domain has expired');
  } else if (error instanceof ValidationError) {
    console.log('Invalid domain name');
  } else if (error instanceof NetworkError) {
    console.log('Network error occurred');
  }
}

Pricing

Domain pricing is based on length and registration duration:

  • 3 characters: 15 S per year
  • 4 characters: 10 S per year
  • 5 characters: 7.5 S per year
  • 6+ characters: 5 S per year

Multi-year Discounts

  • 2 years: 5% discount
  • 3 years: 10% discount
  • 4 years: 15% discount
  • 5 years: 20% discount

Text Record Keys

Common text record keys supported:

import { TEXT_RECORD_KEYS } from 'sns-sdk';

// Standard keys
TEXT_RECORD_KEYS.EMAIL      // 'email'
TEXT_RECORD_KEYS.WEBSITE    // 'website'
TEXT_RECORD_KEYS.AVATAR     // 'avatar'
TEXT_RECORD_KEYS.BANNER     // 'banner'
TEXT_RECORD_KEYS.BIO        // 'bio'

// Social media
TEXT_RECORD_KEYS.X          // 'x'
TEXT_RECORD_KEYS.GITHUB     // 'github'
TEXT_RECORD_KEYS.DISCORD    // 'discord'
TEXT_RECORD_KEYS.INSTAGRAM  // 'instagram'
TEXT_RECORD_KEYS.TELEGRAM   // 'telegram'

Advanced Usage

Custom Network Configuration

import { SNS, getNetworkConfig } from 'sns-sdk';

// Get network config for a specific chain ID
const config = getNetworkConfig(146); // Sonic mainnet
if (config) {
  const sns = new SNS({
    provider,
    registryAddress: config.contracts.registry,
    registrarAddress: config.contracts.registrar,
    resolverAddress: config.contracts.resolver
  });
}

Cache Management

// Clear all caches
sns.clearCache();

// Get cache statistics
const stats = sns.getCacheStats();
console.log(stats.resolver.size); // Number of cached resolver entries
console.log(stats.registry.size); // Number of cached registry entries

Custom Retry Configuration

import { retryWithBackoff } from 'sns-sdk';

// Custom retry logic
const result = await retryWithBackoff(
  async () => await sns.resolve('domain.s'),
  5,    // attempts
  2000  // delay in ms
);

Contract Addresses

Sonic Mainnet (V2)

  • Registry: 0x0A6e0e2a41CD0a4BfB119b2e8183791E21600a7E
  • Registrar: 0x0D9ECE9d71F038444BDB4317a058774867af39eB
  • Resolver: 0x105E9Bfb2f06F4809B0c323Fb8299d813793742e

These addresses are automatically used by the SDK. If you need to use custom addresses, pass them in the configuration.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/your-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Migration Guide: V1 → V2

Breaking Changes

The V2 SDK is mostly backward compatible with V1, but there are a few important changes:

1. Contract Addresses Updated

V2 uses new upgraded contracts. Update your contract addresses if you're using custom addresses:

const sns = new SNS({
  provider,
  registryAddress: '0x...', // V2 registry address
  registrarAddress: '0x...', // V2 registrar address
  resolverAddress: '0x...' // V2 resolver address
});

2. Reverse Records → Primary Names

The old setReverse() method still works but is deprecated. Use setPrimaryName() instead:

// ❌ V1 (deprecated)
await sns.setReverse('mydomain.s', wallet);

// ✅ V2 (recommended)
await sns.setPrimaryName('mydomain.s', wallet);

3. Enhanced Domain Records

The DomainRecord type now includes additional V2 fields:

const info = await sns.getDomainInfo('mydomain.s');

// V2 additions:
info.contenthash   // ENS-compatible contenthash
info.customImage   // Custom NFT image URI

New Features to Adopt

Bulk Operations

Save gas by registering/renewing multiple domains at once:

// Register 3 domains in one transaction
await sns.registerBulk([
  { name: 'domain1', years: 1 },
  { name: 'domain2', years: 2 },
  { name: 'domain3', years: 1 }
], wallet);

Contenthash for IPFS/Swarm

Store decentralized content hashes:

// Set IPFS contenthash
await sns.setContenthash('mydomain.s', '0xe3010170...', wallet);

Batch Text Records

Update multiple text records efficiently:

await sns.setTextBatch('mydomain.s', {
  'email': '[email protected]',
  'com.twitter': '@alice',
  'com.github': 'alice'
}, wallet);

Custom NFT Images

Personalize your domain NFTs:

await sns.setCustomImage('mydomain.s', 'ipfs://QmX...', wallet);

Changelog

v2.0.1 (2026-02)

  • 🆕 Added registerAndConfigure() - Register and configure domain in one transaction
  • ⚡ Gas optimization for domain setup
  • 📝 Documentation improvements

v2.0.0 (2026-01)

  • 🎉 MAJOR UPDATE: Full V2 contract support
  • ✨ Bulk registration and renewal operations
  • 🌐 ENS-compatible contenthash support (IPFS/Swarm)
  • 🎨 Custom NFT images for domains
  • 📝 Batch text record operations
  • 👤 Primary name system (enhanced reverse resolution)
  • 📱 Social media records helper methods
  • 🔄 UUPS upgradeable contract support
  • 💎 ERC-4906 metadata updates
  • 👑 ERC-2981 royalty support

v1.1.0

  • Enhanced type definitions
  • Improved error handling
  • Performance optimizations

v1.0.0

  • Initial release
  • Basic resolution and registration functionality
  • Batch operations support
  • Comprehensive error handling
  • TypeScript support