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

@gaian-sdk/payments

v0.6.4

Published

A powerful SDK for processing cryptocurrency payments via QR codes on the Solana blockchain.

Readme

@gaian-sdk/payments Documentation

A powerful SDK for processing cryptocurrency payments via QR codes on the Solana blockchain.

Installation

npm install @gaian-sdk/payments
# or
yarn add @gaian-sdk/payments

Required Dependencies

npm install @solana/web3.js @solana/spl-token bs58 dotenv

Environment Setup

Create a .env file in your project root:

SOLANA_PRIVATE_KEY=your_base58_encoded_private_key_here
SOLANA_RPC=https://api.devnet.solana.com  # or your preferred RPC endpoint
NODE_ENV=development

Getting Your Private Key

  1. Generate a new keypair (if you don't have one):

    solana-keygen new --outfile ~/.config/solana/id.json
  2. Export as base58 (required format):

    import { Keypair } from "@solana/web3.js";
    import bs58 from "bs58";
    
    // If you have a JSON keypair file
    const keypair = Keypair.fromSecretKey(
      new Uint8Array(JSON.parse(secretKeyArray))
    );
    const privateKeyBase58 = bs58.encode(keypair.secretKey);
    console.log("SOLANA_PRIVATE_KEY=" + privateKeyBase58);
  3. Fund your wallet with SOL and USDC:

    • SOL: solana airdrop 2 YOUR_WALLET_ADDRESS --url devnet
    • USDC: Visit SPL Token Faucet

Basic Usage

1. Initialize the SDK

import { InitializeScanToPay } from "@gaian-sdk/payments";
import { Environment } from "@gaian-sdk/payments/types/common";

const scanToPay = new InitializeScanToPay({
  environment: Environment.DEV, // or Environment.PROD
  paymentsUrl: "http://0.0.0.0:3000", // Your Payments API base URL
  userUrl: "http://0.0.0.0:3000", // Your User API base URL
  timeout: 30000, // 30 second timeout
  solanaRpcUrl: process.env.SOLANA_RPC,
});

2. Set Up Solana Connection

import { Connection, Keypair, Transaction } from "@solana/web3.js";
import bs58 from "bs58";

// Load your keypair from environment
function loadKeypairFromEnv() {
  const privateKeyBase58 = process.env.SOLANA_PRIVATE_KEY;
  if (!privateKeyBase58) throw new Error("SOLANA_PRIVATE_KEY required");
  return Keypair.fromSecretKey(bs58.decode(privateKeyBase58));
}

const connection = new Connection(process.env.SOLANA_RPC || "");

User Registration and KYC

Before processing payments, users need to be registered and complete KYC verification.

User Registration

const userResult = await scanToPay.registerUser({
  email: "[email protected]",
  walletAddress: "AYwJ2JCteMY2FxSJXjFpkCSxTvff1wzHgFrT1iDJpi8W", // Solana wallet address
});

console.log("User registered:", userResult);
// Returns: { user: { id: number, email: string, walletAddress: string } }

Generate KYC Link

const kycResult = await scanToPay.generateKYCLink({
  userId: userResult.user.id.toString(),
  email: userResult.user.email,
  phone: "+1234567890", // Optional phone number
});

console.log("KYC link:", kycResult);
// Returns KYC link for user verification

Complete User Registration Example

import { InitializeScanToPay, Environment } from "@gaian-sdk/payments";
import "dotenv/config";

async function registerUserAndKYC() {
  const scanToPay = new InitializeScanToPay({
    environment: Environment.DEV,
    paymentsUrl: "http://0.0.0.0:3000",
    userUrl: "http://0.0.0.0:3000",
    timeout: 30000,
  });

  try {
    // 1. Register User
    console.log("📝 Registering user...");
    const userResult = await scanToPay.registerUser({
      email: "[email protected]",
      walletAddress: "AYwJ2JCteMY2FxSJXjFpkCSxTvff1wzHgFrT1iDJpi8W",
    });
    console.log("✅ User registered:", userResult);

    // 2. Generate KYC Link
    console.log("🔗 Generating KYC link...");
    const kycResult = await scanToPay.generateKYCLink({
      userId: userResult.user.id.toString(),
      email: userResult.user.email,
      phone: "+1234567890",
    });
    console.log("✅ KYC link generated:", kycResult);

    return { success: true, userResult, kycResult };
  } catch (error) {
    console.error("❌ Registration failed:", error);
    return { success: false, error };
  }
}

registerUserAndKYC();

Complete Payment Flow

Step 1: Place an Order

const orderResult = await scanToPay.placeOrder({
  qrString:
    "00020101021138520010A000000727012200069704160108355454570208QRIBFTTA53037045802VN6304B345",
  amount: 15000, // Amount in minor units (15000 = 15.000 VND)
  fiatCurrency: "VND", // Target fiat currency
  cryptoCurrency: "USDC", // Crypto currency to use
  fromAddress: "YOUR_WALLET_ADDRESS", // Your Solana wallet address
  chain: "Solana",
});

console.log("Order ID:", orderResult.orderId);
console.log("Status:", orderResult.status); // Should be "awaiting_crypto_transfer"

Step 2: Decode and Prepare Transaction

// The SDK returns a Legacy Transaction (not Versioned)
const transaction = await scanToPay.decodeTransaction(orderResult);

console.log("Fee Payer:", transaction.feePayer?.toString());
console.log("Instructions:", transaction.instructions.length);
console.log("Blockhash:", transaction.recentBlockhash);

Step 3: Sign and Submit Transaction

async function signAndSubmitTransaction(
  transaction: Transaction,
  connection: Connection
) {
  const payer = loadKeypairFromEnv();

  try {
    // Get fresh blockhash for better reliability
    const { blockhash } = await connection.getLatestBlockhash("confirmed");

    // Sign the transaction
    transaction.sign(payer);
    console.log("✅ Transaction signed successfully");

    // Submit transaction
    const txid = await connection.sendRawTransaction(transaction.serialize(), {
      skipPreflight: true,
      maxRetries: 3,
    });

    console.log("📤 Transaction submitted:", txid);
    return txid;
  } catch (error) {
    console.error("Transaction failed:", error);
    throw error;
  }
}

const transactionHash = await signAndSubmitTransaction(transaction, connection);

Step 4: Verify the Order

// Wait a moment for transaction confirmation
await new Promise((resolve) => setTimeout(resolve, 10000));

const verifyResult = await scanToPay.verifyOrder({
  orderId: orderResult.orderId,
  transactionProof: transactionHash,
});

console.log("Verified:", verifyResult.status);

Step 5: Check Final Status

const statusResult = await scanToPay.getStatus({
  orderId: orderResult.orderId,
});

console.log("Final Status:", statusResult.status);

Order History

The SDK provides methods to retrieve order history for users, which can be useful for displaying transaction records and tracking payment activity.

Get Order History by User Email/ID

Retrieve order history using a user's email address or user ID:

const orderHistory = await scanToPay.getOrderHistoryByUserName({
  identifier: "[email protected]", // Email address or user ID
  page: 1, // Page number (optional, defaults to 1)
  limit: 20, // Number of orders per page (optional, defaults to 20)
});

console.log("Order history:", orderHistory);
// Returns: { status, data: { user, orders: { items, pagination } } }

Get Order History by Wallet Address

Retrieve order history using a Solana wallet address:

const orderHistory = await scanToPay.getOrderHistoryByWallet({
  walletAddress: "AYwJ2JCteMY2FxSJXjFpkCSxTvff1wzHgFrT1iDJpi8W",
  page: 1, // Page number (optional, defaults to 1)
  limit: 20, // Number of orders per page (optional, defaults to 20)
});

console.log("Order history:", orderHistory);
// Returns: { status, data: { user, orders: { items, pagination } } }

Complete Order History Example

import { InitializeScanToPay, Environment } from "@gaian-sdk/payments";
import "dotenv/config";

async function getOrderHistory() {
  const scanToPay = new InitializeScanToPay({
    environment: Environment.DEV,
    paymentsUrl: "https://gaian-payments-backend-3.onrender.com",
    userUrl: "http://127.0.0.1:3000",
    timeout: 30000,
  });

  try {
    // Get order history by email
    console.log("📋 Fetching order history by email...");
    const historyByEmail = await scanToPay.getOrderHistoryByUserName({
      identifier: "[email protected]",
      page: 1,
      limit: 10,
    });
    
    console.log("✅ Order history by email:", historyByEmail.data.orders.items);
    console.log("📄 Pagination:", historyByEmail.data.orders.pagination);

    // Get order history by wallet address
    console.log("📋 Fetching order history by wallet...");
    const historyByWallet = await scanToPay.getOrderHistoryByWallet({
      walletAddress: "AYwJ2JCteMY2FxSJXjFpkCSxTvff1wzHgFrT1iDJpi8W",
      page: 1,
      limit: 10,
    });
    
    console.log("✅ Order history by wallet:", historyByWallet.data.orders.items);
    console.log("📄 Pagination:", historyByWallet.data.orders.pagination);

  } catch (error) {
    console.error("❌ Failed to fetch order history:", error);
  }
}

getOrderHistory();

Error Handling

try {
  // Your payment flow code here
} catch (error) {
  console.error("Payment failed:", error);

  // Handle specific error types
  if (error.message.includes("insufficient funds")) {
    console.log("💡 Please fund your wallet with SOL and USDC");
  } else if (error.message.includes("blockhash")) {
    console.log("💡 Try again - blockhash expired");
  }
}

Complete Example

import { InitializeScanToPay, Environment } from "@gaian-sdk/payments";
import { Connection, Keypair, Transaction } from "@solana/web3.js";
import bs58 from "bs58";
import "dotenv/config";

async function processPayment() {
  // Initialize SDK
  const scanToPay = new InitializeScanToPay({
    environment: Environment.DEV,
    paymentsUrl: "http://0.0.0.0:3000",
    userUrl: "http://0.0.0.0:3000",
    timeout: 30000,
    solanaRpcUrl: process.env.SOLANA_RPC,
  });

  const connection = new Connection(process.env.SOLANA_RPC || "");
  const payer = Keypair.fromSecretKey(
    bs58.decode(process.env.SOLANA_PRIVATE_KEY!)
  );

  try {
    // 1. Place order
    const order = await scanToPay.placeOrder({
      qrString: "YOUR_QR_CODE_STRING",
      amount: 15000,
      fiatCurrency: "VND",
      cryptoCurrency: "USDC",
      fromAddress: payer.publicKey.toString(),
      chain: "Solana",
    });

    // 2. Decode transaction
    const transaction = await scanToPay.decodeTransaction(order);

    // 3. Sign and submit
    transaction.sign(payer);
    const txHash = await connection.sendRawTransaction(
      transaction.serialize(),
      {
        skipPreflight: true,
        maxRetries: 3,
      }
    );

    // 4. Wait and verify
    await new Promise((resolve) => setTimeout(resolve, 10000));

    const verification = await scanToPay.verifyOrder({
      orderId: order.orderId,
      transactionProof: txHash,
    });

    // 5. Get final status
    const status = await scanToPay.getStatus({ orderId: order.orderId });

    console.log("Payment completed:", {
      orderId: order.orderId,
      transactionHash: txHash,
      verified: verification.status,
      finalStatus: status.status,
    });
  } catch (error) {
    console.error("Payment failed:", error);
  }
}

processPayment();

API Reference

InitializeScanToPay Constructor Options

| Property | Type | Description | | -------------- | ------------------------------------- | ------------------------------- | | environment | Environment.DEV \| Environment.PROD | SDK environment | | paymentsUrl | string | Payments API base URL | | userUrl | string | User API base URL | | timeout | number | Request timeout in milliseconds | | solanaRpcUrl | string | Solana RPC endpoint URL |

registerUser(params)

Registers a new user in the system.

Parameters:

  • email: User's email address
  • walletAddress: User's Solana wallet address

Returns: User object with id, email, and walletAddress

generateKYCLink(params)

Generates a KYC verification link for a registered user.

Parameters:

  • userId: User ID from registration (as string)
  • email: User's email address
  • phone: User's phone number (optional)

Returns: KYC link object for user verification

placeOrder(params)

Places a new payment order.

Parameters:

  • qrString: QR code string to process
  • amount: Payment amount in minor currency units
  • fiatCurrency: Target fiat currency (e.g., "VND")
  • cryptoCurrency: Cryptocurrency to use (e.g., "USDC")
  • fromAddress: Your Solana wallet address
  • chain: Blockchain name ("Solana")

Returns: Order object with orderId and status

decodeTransaction(orderResult)

Decodes the payment transaction from an order.

Parameters:

  • orderResult: Result from placeOrder()

Returns: Solana Transaction object (Legacy format)

verifyOrder(params)

Verifies a completed transaction.

Parameters:

  • orderId: Order ID from placeOrder()
  • transactionProof: Transaction hash from blockchain

Returns: Verification result with status

getStatus(params)

Gets the current status of an order.

Parameters:

  • orderId: Order ID to check

Returns: Status object with current order state

getOrderHistoryByUserName(params)

Gets order history for a user by email or user ID.

Parameters:

  • identifier: User's email address or user ID
  • page: Page number (optional, defaults to 1)
  • limit: Number of orders per page (optional, defaults to 20)

Returns: Object containing user information and paginated order history

getOrderHistoryByWallet(params)

Gets order history for a user by wallet address.

Parameters:

  • walletAddress: User's Solana wallet address
  • page: Page number (optional, defaults to 1)
  • limit: Number of orders per page (optional, defaults to 20)

Returns: Object containing user information and paginated order history

Troubleshooting

Common Issues

  1. "SOLANA_PRIVATE_KEY required"

    • Ensure your .env file has the private key in base58 format
  2. "insufficient funds"

    • Fund your wallet with SOL for transaction fees
    • Fund your wallet with USDC for payments
  3. "blockhash not found"

    • The transaction took too long - retry with a fresh transaction
  4. Network timeouts

    • Check your RPC endpoint is working
    • Try increasing the timeout value
  5. User registration errors

    • Verify email format is valid
    • Ensure wallet address is a valid Solana public key
    • Check that userUrl is correctly configured

Getting Test Tokens

For development/testing on devnet:

Checking Balances

// Check SOL balance
const balance = await connection.getBalance(payer.publicKey);
console.log("SOL balance:", balance / 1e9);

// Check USDC balance
import { getAssociatedTokenAddress, getAccount } from "@solana/spl-token";

const USDC_MINT = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"; // Devnet
const ata = await getAssociatedTokenAddress(
  new PublicKey(USDC_MINT),
  payer.publicKey
);
const tokenAccount = await getAccount(connection, ata);
console.log("USDC balance:", Number(tokenAccount.amount) / 1e6);

Support

For issues and questions:

  • Check the troubleshooting section above
  • Review your environment setup
  • Ensure your wallet has sufficient funds
  • Verify your RPC endpoint is responsive