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

@bbuilders/djeon402-sdk-node

v2.0.1

Published

DJEON402 SDK for Node.js and Backend applications

Readme

@bbuilders/djeon402-sdk-node

Official Node.js SDK for DJEON402 token - designed for backend and server-side applications.

What's New in 2.0

Breaking changes:

  • Token decimals are 6 (USDC/x402 convention) — USD/amount conversions use parseTokenAmount (no more float precision loss)
  • kyc.checkDailyLimit now returns the real allow/deny boolean (simulates first, records on-chain only when allowed; caller must be KYC admin or approved provider)
  • Custom chain ids now get a proper chain definition (previously any non-Base chain was signed as Foundry/31337)

New:

  • kyc.verify accepts an optional kycHash; when omitted it is derived deterministically from documents (no more random placeholder hash)

Overview

@bbuilders/djeon402-sdk-node provides a comprehensive, type-safe interface for interacting with DJEON402 smart contracts from Node.js environments. It handles all the complexity of blockchain interactions, signing, and transaction management.

Key Features:

  • Full ERC-20 token operations (transfer, approve, mint, burn)
  • Admin functions (roles, blacklist, pause/unpause)
  • KYC management (verify, check status, limits)
  • x402/EIP-3009 gasless transactions
  • Built on viem for type safety and performance
  • Server-side signing with private keys
  • Support for Foundry (Anvil), Base, and custom EVM networks

Units

The token uses 6 decimals (USDC/x402 convention): $1 = 1_000_000 base units. Human-readable amount params (e.g. '100.5') are converted internally via parseTokenAmount — pass token units, not base units.

Installation

npm install @bbuilders/djeon402-sdk-node
# or
pnpm add @bbuilders/djeon402-sdk-node
# or
yarn add @bbuilders/djeon402-sdk-node

Quick Start

import { Djeon402NodeSDK } from '@bbuilders/djeon402-sdk-node';

// Configuration constants
const DJEON402_CONTRACT = '0x....';
const KYC_REGISTRY = '0x....';
const RPC_URL = 'http://localhost:8545'; // Anvil local node
const CHAIN_ID = 31337; // Foundry

// Test account addresses
const TEST_ACCOUNT = '0x.....';
const RECIPIENT_ADDRESS = '0x....';

// Initialize SDK
const sdk = new Djeon402NodeSDK({
  rpcUrl: RPC_URL,
  contractAddress: DJEON402_CONTRACT,
  kycRegistryAddress: KYC_REGISTRY,
  chainId: CHAIN_ID,
});

// Get token info
const info = await sdk.token.getInfo();
console.log(`Token: ${info.name} (${info.symbol})`);
console.log(`Total Supply: ${info.totalSupply}`);

// Check balance
const balance = await sdk.token.getBalance(TEST_ACCOUNT);
console.log(`Balance: ${balance.balance} DJEON`);

// Transfer tokens
const result = await sdk.token.transfer({
  privateKey: process.env.PRIVATE_KEY!,
  to: RECIPIENT_ADDRESS,
  amount: '100.5',
});
console.log(`Transfer successful! Hash: ${result.hash}`);

Configuration

Constructor Options

interface SDKConfig {
  rpcUrl: string;              // Blockchain RPC endpoint
  contractAddress: Address;    // DJEON402 token contract address
  kycRegistryAddress?: Address; // Optional KYC registry address
  chainId: number;             // 31337 (Foundry) or 8453 (Base)
}

Supported Networks

  • Foundry (Anvil): chainId: 31337
  • Base: chainId: 8453
  • Other EVM chains: any other chainId gets a minimal chain definition built from rpcUrl, so transactions are signed with the correct chain id

API Reference

Token Module (sdk.token)

getInfo()

Get token information.

const info = await sdk.token.getInfo();
// Returns: { name, symbol, decimals, totalSupply, paused, contractAddress }

getBalance(address)

Get token balance for an address.

const balance = await sdk.token.getBalance('0x742d35...');
// Returns: { address, balance, balanceRaw }

getAllowance(owner, spender)

Get allowance amount.

const allowance = await sdk.token.getAllowance(
  '0xOwner...',
  '0xSpender...'
);
// Returns: { owner, spender, allowance, allowanceRaw }

transfer({ privateKey, to, amount })

Transfer tokens.

const result = await sdk.token.transfer({
  privateKey: '0xYourPrivateKey',
  to: '0xRecipient...',
  amount: '100.5', // Human-readable amount
});
// Returns: { success, hash, blockNumber }

approve({ privateKey, spender, amount })

Approve spending allowance.

const result = await sdk.token.approve({
  privateKey: '0xYourPrivateKey',
  spender: '0xSpender...',
  amount: '1000',
});

mint({ privateKey, to, amount }) (Admin only)

Mint new tokens.

const result = await sdk.token.mint({
  privateKey: '0xAdminPrivateKey',
  to: '0xRecipient...',
  amount: '500',
});

burn({ privateKey, amount }) (Admin only)

Burn tokens.

const result = await sdk.token.burn({
  privateKey: '0xAdminPrivateKey',
  amount: '100',
});

Admin Module (sdk.admin)

getRoles()

Get all role identifiers.

const roles = await sdk.admin.getRoles();
// Returns: { DEFAULT_ADMIN_ROLE, MINTER_ROLE, BURNER_ROLE, PAUSER_ROLE, BLACKLISTER_ROLE }

hasRole(role, account)

Check if account has a role.

const result = await sdk.admin.hasRole(
  '0xRoleHash...',
  '0xAccount...'
);
// Returns: { role, address, hasRole }

isBlacklisted(address)

Check if address is blacklisted.

const result = await sdk.admin.isBlacklisted('0xAddress...');
// Returns: { address, isBlacklisted }

blacklist({ privateKey, account })

Add address to blacklist.

const result = await sdk.admin.blacklist({
  privateKey: '0xAdminPrivateKey',
  account: '0xBadActor...',
});

unBlacklist({ privateKey, account })

Remove address from blacklist.

const result = await sdk.admin.unBlacklist({
  privateKey: '0xAdminPrivateKey',
  account: '0xAccount...',
});

pause(privateKey) / unpause(privateKey)

Pause/unpause the contract.

await sdk.admin.pause('0xAdminPrivateKey');
await sdk.admin.unpause('0xAdminPrivateKey');

KYC Module (sdk.kyc)

getData(address)

Get KYC data for a user.

const kyc = await sdk.kyc.getData('0xUser...');
// Returns: { level, levelName, expiryDate, kycHash, isActive, dailyLimit, dailySpent, ... }

verify({ adminPrivateKey, userAddress, level, expiryDate?, documents, kycHash? })

Verify user's KYC. When kycHash is omitted it is derived deterministically (keccak256) from documents; pass your own IPFS hash for real deployments.

const result = await sdk.kyc.verify({
  adminPrivateKey: '0xAdminPrivateKey',
  userAddress: '0xUser...',
  level: 2, // 0: None, 1: Tier1, 2: Tier2, 3: Tier3, 4: Tier4
  expiryDate: Math.floor(Date.now() / 1000) + 365 * 24 * 60 * 60, // 1 year
  documents: [
    { filename: 'passport.pdf', content: 'base64data...' },
    { filename: 'proof.pdf', content: 'base64data...' },
  ],
  kycHash: 'QmYourIpfsHash...', // optional
});

updateKYC({ adminPrivateKey, userAddress, level, expiryDate? }) / revokeKYC({ adminPrivateKey, userAddress })

Update or revoke an existing KYC record (admin only).

isKYCValid(address)

Check whether a user's KYC is active, non-None, and not expired.

const valid = await sdk.kyc.isKYCValid('0xUser...'); // boolean

checkDailyLimit({ adminPrivateKey, userAddress, amountUSD })

Check whether an amount fits the user's daily limit and record the spend. This contract function is state-mutating, so the SDK simulates first and returns the real allow/deny boolean; the transaction is only sent when the spend is allowed. The caller must be the KYC admin or an approved provider. For a read-only check use getRemainingDailyLimit.

const allowed = await sdk.kyc.checkDailyLimit({
  adminPrivateKey: '0xAdminPrivateKey',
  userAddress: '0xUser...',
  amountUSD: '250',
}); // boolean

getRemainingDailyLimit(address)

Read-only remaining daily limit.

const remaining = await sdk.kyc.getRemainingDailyLimit('0xUser...');
// Returns: bigint in base units (type(uint256).max when unlimited)

setDailyLimit({ adminPrivateKey, userAddress, limitUSD })

Set a custom per-user daily limit (admin only).

setLevelLimit({ adminPrivateKey, level, limitUSD })

Set default daily limit for a KYC level (admin only).

// Change Tier2 daily limit to $20,000
const result = await sdk.kyc.setLevelLimit({
  adminPrivateKey: '0xAdminPrivateKey',
  level: 2,
  limitUSD: '20000',
});

getLevelLimit(level)

Get default daily limit for a KYC level.

const limit = await sdk.kyc.getLevelLimit(2); // Tier2
// Returns: bigint (e.g. 10000000000n for $10,000 with 6 decimals)

x402 Module (sdk.x402)

EIP-3009 gasless transactions - allows users to authorize transfers without paying gas.

generateNonce()

Generate a unique nonce for authorization.

const nonce = sdk.x402.generateNonce();
// Returns: '0x........'

getDomainSeparator()

Get EIP-712 domain separator. Signing methods read this from the contract, so signatures stay valid for any deploy-time token name — never hardcode the domain name.

const separator = await sdk.x402.getDomainSeparator();

getAuthorizationState(authorizer, nonce)

Check if a nonce has been used.

const isUsed = await sdk.x402.getAuthorizationState('0xAuthorizer...', '0xNonce...');
// Returns: boolean

signTransfer({ privateKey, from, to, amount, ... })

Sign a transfer authorization (payer side).

const signature = await sdk.x402.signTransfer({
  privateKey: '0xPayerPrivateKey',
  from: '0xPayer...',
  to: '0xRecipient...',
  amount: '50',
  validAfter: BigInt(Math.floor(Date.now() / 1000)),
  validBefore: BigInt(Math.floor(Date.now() / 1000) + 3600),
  nonce: sdk.x402.generateNonce(),
});
// Returns: { from, to, value, validAfter, validBefore, nonce, v, r, s }

executeTransfer({ executorPrivateKey, authorization })

Execute a signed transfer authorization (executor/relayer side).

const result = await sdk.x402.executeTransfer({
  executorPrivateKey: '0xExecutorPrivateKey',
  authorization: signature,
});
// Returns: { success, hash, blockNumber }

signReceive({ privateKey, from, to, amount, ... })

Sign a receive authorization (payee side). The sender signs to authorize the receiver to pull funds.

const signature = await sdk.x402.signReceive({
  privateKey: '0xSenderPrivateKey',
  from: '0xSender...',
  to: '0xReceiver...',
  amount: '50',
});
// Returns: { from, to, value, validAfter, validBefore, nonce, v, r, s }

executeReceive({ receiverPrivateKey, authorization })

Execute a signed receive authorization. The caller must be the receiver (to address).

const result = await sdk.x402.executeReceive({
  receiverPrivateKey: '0xReceiverPrivateKey',
  authorization: signature,
});
// Returns: { success, hash, blockNumber }

cancelAuthorization({ privateKey, authorizer, nonce })

Cancel an authorization by marking the nonce as used.

const result = await sdk.x402.cancelAuthorization({
  privateKey: '0xAuthorizerPrivateKey',
  authorizer: '0xAuthorizer...',
  nonce: '0xNonce...',
});
// Returns: { success, hash, blockNumber }

Complete x402 Payment Flow

// Step 1: User signs authorization (no gas needed)
const authorization = await sdk.x402.signTransfer({
  privateKey: '0xUserPrivateKey',
  from: '0xUser...',
  to: '0xMerchant...',
  amount: '99.99',
});

// Step 2: Relayer/backend executes the transfer (pays gas)
const result = await sdk.x402.executeTransfer({
  executorPrivateKey: '0xRelayerPrivateKey',
  authorization,
});

console.log(`Payment processed! Hash: ${result.hash}`);

Receive Flow (Payee-Initiated)

// Step 1: Sender signs receive authorization
const authorization = await sdk.x402.signReceive({
  privateKey: '0xSenderPrivateKey',
  from: '0xSender...',
  to: '0xReceiver...',
  amount: '50',
});

// Step 2: Receiver executes (pulls funds)
const result = await sdk.x402.executeReceive({
  receiverPrivateKey: '0xReceiverPrivateKey',
  authorization,
});

Direct Blockchain Access

Access the underlying viem public client for custom operations:

// Get current block number
const blockNumber = await sdk.publicClient.getBlockNumber();

// Get ETH balance
const ethBalance = await sdk.publicClient.getBalance({
  address: '0x......',
});

// Read custom contract method
const result = await sdk.publicClient.readContract({
  address: sdk.contractAddress,
  abi: [...],
  functionName: 'customMethod',
  args: [...],
});

Error Handling

All SDK methods may throw errors. Always wrap calls in try-catch blocks:

try {
  const result = await sdk.token.transfer({
    privateKey: '0x...',
    to: '0x...',
    amount: '100',
  });
  console.log('Success:', result.hash);
} catch (error) {
  if (error instanceof Error) {
    console.error('Transfer failed:', error.message);
  }
}

Examples

Backend API Integration

import { Djeon402NodeSDK } from '@bbuilders/djeon402-sdk-node';
import express from 'express';

// Configuration from environment variables
const RPC_URL = process.env.RPC_URL!;
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS as `0x${string}`;
const CHAIN_ID = parseInt(process.env.CHAIN_ID || '31337');
const PRIVATE_KEY = process.env.PRIVATE_KEY as `0x${string}`;

const sdk = new Djeon402NodeSDK({
  rpcUrl: RPC_URL,
  contractAddress: CONTRACT_ADDRESS,
  chainId: CHAIN_ID,
});

const app = express();

app.post('/api/transfer', async (req, res) => {
  try {
    const { to, amount } = req.body;
    const result = await sdk.token.transfer({
      privateKey: PRIVATE_KEY,
      to,
      amount,
    });
    res.json({ success: true, hash: result.hash });
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

app.get('/api/balance/:address', async (req, res) => {
  try {
    const balance = await sdk.token.getBalance(req.params.address as `0x${string}`);
    res.json(balance);
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

app.listen(3000);

Automated KYC Verification

async function verifyUserKYC(userAddress: string, documents: any[]) {
  // Configuration constants
  const RPC_URL = process.env.RPC_URL!;
  const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS as `0x${string}`;
  const CHAIN_ID = parseInt(process.env.CHAIN_ID || '31337');
  const ADMIN_PRIVATE_KEY = process.env.ADMIN_KEY as `0x${string}`;

  // KYC settings
  const KYC_LEVEL = 2; // Tier2
  const EXPIRY_DAYS = 365;
  const EXPIRY_TIMESTAMP = Math.floor(Date.now() / 1000) + EXPIRY_DAYS * 24 * 60 * 60;

  const sdk = new Djeon402NodeSDK({
    rpcUrl: RPC_URL,
    contractAddress: CONTRACT_ADDRESS,
    chainId: CHAIN_ID,
  });

  // Verify user with Tier2 access
  const result = await sdk.kyc.verify({
    adminPrivateKey: ADMIN_PRIVATE_KEY,
    userAddress: userAddress as `0x${string}`,
    level: KYC_LEVEL,
    expiryDate: EXPIRY_TIMESTAMP,
    documents,
  });

  // Check KYC data
  const kycData = await sdk.kyc.getData(userAddress as `0x${string}`);
  console.log(`User verified: ${kycData.levelName}`);
  console.log(`Daily limit: ${kycData.dailyLimit} USD`);

  return result;
}

Gasless Payment Relayer

import { Djeon402NodeSDK } from '@bbuilders/djeon402-sdk-node';

// Configuration constants
const RPC_URL = process.env.RPC_URL!;
const CONTRACT_ADDRESS = process.env.CONTRACT_ADDRESS as `0x${string}`;
const CHAIN_ID = parseInt(process.env.CHAIN_ID || '31337');
const RELAYER_PRIVATE_KEY = process.env.RELAYER_KEY as `0x${string}`;

const sdk = new Djeon402NodeSDK({
  rpcUrl: RPC_URL,
  contractAddress: CONTRACT_ADDRESS,
  chainId: CHAIN_ID,
});

// User submits signed authorization to your API
app.post('/api/relay-payment', async (req, res) => {
  const { authorization } = req.body;

  try {
    // Your backend pays the gas
    const result = await sdk.x402.executeTransfer({
      executorPrivateKey: RELAYER_PRIVATE_KEY,
      authorization,
    });

    res.json({
      success: true,
      hash: result.hash,
      message: 'Payment processed without user paying gas',
    });
  } catch (error: any) {
    res.status(500).json({ error: error.message });
  }
});

TypeScript Support

This SDK is written in TypeScript and provides full type definitions:

import type {
  TokenInfo,
  BalanceResult,
  TransferResult,
  KYCData,
  TransferAuthorizationSignature,
  ReceiveAuthorizationSignature,
  CancelAuthorizationParams,
  CancelAuthorizationResult,
} from '@bbuilders/djeon402-sdk-node';

Security Notes

  • Private Keys: Never expose private keys in client-side code. This SDK is designed for server-side use only.
  • Environment Variables: Store private keys and sensitive data in environment variables.
  • Input Validation: The SDK validates addresses, amounts, and private keys, but you should still validate user input.
  • Rate Limiting: Implement rate limiting on your API endpoints to prevent abuse.

Related Packages

License

MIT