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

@rotateprotocol/sdk

v1.0.2

Published

Rotate Protocol SDK - The easiest way to accept payments on Solana. Non-custodial, instant settlement.

Readme

@rotateprotocol/sdk

Accept Solana payments in minutes. Non-custodial, instant settlement.

Install

npm install @rotateprotocol/sdk

Quick Start (React)

import { RotateProvider, PaymentButton } from '@rotateprotocol/sdk/components';

function App() {
  return (
    <RotateProvider merchantId={1000000} platformId={1000000}>
      <PaymentButton 
        amount={29.99}
        onSuccess={(payment) => console.log('Paid!', payment)}
      />
    </RotateProvider>
  );
}

Quick Start (HTML)

<script src="https://js.rotatepay.io/embed.js"></script>

<button 
  data-rotate-pay 
  data-amount="29.99" 
  data-merchant="1000000" 
  data-platform="1000000"
>
  Pay $29.99
</button>

Creating Platforms & Merchants

import RotateSDK from '@rotateprotocol/sdk';

const sdk = new RotateSDK({ network: 'mainnet-beta' });
sdk.initWithWallet(wallet);

// Create platform (one-time) — ID assigned automatically
const { platformId } = await sdk.createPlatform({
  feeBps: 300, // 3% platform fee
  wallet: wallet.publicKey,
});

// Create merchant (one-time)
const { merchantId } = await sdk.createMerchant({
  platformId,
  wallet: wallet.publicKey,
});

Creating Payment Links

// USD link — buyer chooses SOL, USDC, or USDT
const { linkId } = await sdk.createLinkUsd({
  merchantId, platformId,
  amount: 25_000_000n, // $25.00 (micro-USD, 6 decimals)
  allowTips: true,
});

// SOL link
const { linkId } = await sdk.createLinkSol({
  merchantId, platformId,
  amount: 500_000_000n, // 0.5 SOL (lamports, 9 decimals)
});

// USDC/USDT link
const { linkId } = await sdk.createLinkToken({
  merchantId, platformId,
  amount: 25_000_000n, // $25.00
  currency: 'USDC', // or 'USDT'
});

Link Types

| Type | Method | Amount Unit | Buyer Pays With | |------|--------|-------------|-----------------| | USD | createLinkUsd | Micro-USD (6 dec) | SOL, USDC, or USDT | | SOL | createLinkSol | Lamports (9 dec) | SOL only | | USDC | createLinkToken | Micro-USDC (6 dec) | USDC only | | USDT | createLinkToken | Micro-USDT (6 dec) | USDT only |

Tips

Set allowTips: true when creating a link. Tips go 100% to the merchant — no fees on tips. Capped at 100% of the payment amount.

Expiration

E-commerce links auto-expire after 5 minutes. Dashboard links can be manually cancelled.


Checking Payment Status

// Get link status
const link = await sdk.getPaymentLink(linkId);
console.log(link.status); // 'Pending' | 'Paid' | 'Cancelled'

// Check if paid
const isPaid = await sdk.isLinkPaid(linkId);

// Wait for payment (with timeout)
const result = await sdk.waitForPayment(linkId, 300_000); // 5 min

// Get checkout URL
const url = sdk.getPaymentUrl(linkId);

React Components

PaymentButton

import { PaymentButton } from '@rotateprotocol/sdk/components';

<PaymentButton 
  amount={99.99}
  currency="USD"
  label="Buy Now"
  variant="solid"       // 'solid' | 'outline' | 'ghost'
  size="lg"             // 'sm' | 'md' | 'lg'
  allowTips={true}
  onSuccess={(payment) => router.push('/success')}
  onError={(error) => alert(error.message)}
/>

CheckoutForm

import { CheckoutForm } from '@rotateprotocol/sdk/components';

<CheckoutForm 
  amount={149.99}
  productName="Pro Plan"
  productDescription="Unlimited access for 1 year"
  allowTips={true}
  showCurrencySelector={true}
  onSuccess={(payment) => fulfillOrder(payment.linkId)}
/>

HostedCheckout

import { HostedCheckout } from '@rotateprotocol/sdk/components';

<HostedCheckout 
  linkId={12345}
  merchantId={1000000}
  platformId={1000000}
  brandName="My Store"
  brandColor="#8B5CF6"
  onSuccess={(result) => window.location.href = '/success'}
/>

React Hooks

import { usePaymentLink, useSolPrice, useRotate, useCreateEntities, useTokenBalances } from '@rotateprotocol/sdk/react';

// Payment status
const { link, status, startPolling, stopPolling } = usePaymentLink(linkId);

// SOL price
const { price, usdToSol, solToUsd } = useSolPrice();

// SDK instance
const { sdk, connected, publicKey } = useRotate({ network: 'mainnet-beta' });

// Create entities
const { createPlatform, createMerchant, creating } = useCreateEntities();

// Token balances
const { balances, hasEnough } = useTokenBalances();

Vanilla JavaScript

<script src="https://js.rotatepay.io/embed.js"></script>

<script>
  Rotate.configure({ network: 'mainnet-beta' });

  // Open checkout popup
  Rotate.checkout({
    amount: 29.99,
    merchantId: 1000000,
    platformId: 1000000,
    allowTips: true,
    onSuccess: (payment) => console.log('Paid!', payment),
  });
</script>

Data Attributes

| Attribute | Description | Example | |-----------|-------------|---------| | data-rotate-pay | Marks as payment button | (no value) | | data-amount | Amount | "29.99" | | data-merchant | Merchant ID | "1000000" | | data-platform | Platform ID | "1000000" | | data-currency | Currency | "USD", "SOL" | | data-tips | Allow tips | "true" | | data-brand | Brand name | "My Store" | | data-color | Brand color | "8B5CF6" |


Webhooks

import { EventListener, verifyWebhookSignature } from '@rotateprotocol/sdk/webhooks';

const listener = new EventListener({
  network: 'mainnet-beta',
  merchantId: 1000000,
});

listener.on('payment.completed', async (event) => {
  await fulfillOrder(event.data.orderRef);
});

listener.start();

Server-Side Verification

app.post('/api/webhooks/rotate', async (req, res) => {
  const signature = req.headers['x-rotate-signature'];
  const isValid = await verifyWebhookSignature(
    JSON.stringify(req.body), signature, process.env.WEBHOOK_SECRET
  );
  if (!isValid) return res.status(401).json({ error: 'Invalid signature' });

  if (req.body.type === 'payment.completed') {
    await fulfillOrder(req.body.data.orderRef);
  }
  res.json({ received: true });
});

Events

| Event | When | |-------|------| | payment.completed | Payment successful | | payment.pending | Payment started | | link.created | New link created | | link.cancelled | Link cancelled | | link.expired | Link expired |


Platform Merchant Onboarding

For marketplaces that need to onboard sellers:

import { RotatePlatformManager } from '@rotateprotocol/sdk/platform';

const manager = new RotatePlatformManager(sdk, { platformId: 1000000 });

// Onboard a seller
const { merchantId } = await manager.onboardMerchant({
  wallet: sellerAddress,
  name: 'Coffee Shop',
  metadata: { location: 'NYC' },
});

// Bulk onboard
const results = await manager.onboardMerchants(sellers, {
  onProgress: (i, total) => console.log(`${i}/${total}`),
});

// Stats
const stats = await manager.getStats();

// Export/import directory for persistence
const data = manager.exportDirectory();
manager.importDirectory(data);

Only the merchant's wallet owner can update their account. Platform admins cannot modify merchant settings after creation.


Store & Marketplace

import { RotateStore } from '@rotateprotocol/sdk/store';
import { RotateMarketplace } from '@rotateprotocol/sdk/marketplace';

// Single-vendor store
const store = new RotateStore(sdk, { merchantId: 1000000, platformId: 1000000 });
store.addProducts([{ id: 'tshirt', name: 'Logo Tee', price: 29.99, inventory: 100 }]);
store.addDiscount({ code: 'SAVE10', type: 'percent', value: 10 });
const cart = store.createCart();
cart.addItem('tshirt', 2);
cart.applyDiscount('SAVE10');
const { paymentUrl } = await cart.checkout();

// Multi-vendor marketplace
const marketplace = new RotateMarketplace(sdk, { platformId: 1000000, platformFeeBps: 200 });
marketplace.addVendor({ id: 'vendor-a', merchantId: 1000001, name: 'Shirt Co.' });
marketplace.addProduct({ id: 'shirt-1', vendorId: 'vendor-a', name: 'Logo Tee', price: 29.99 });
const mktCart = marketplace.createCart();
mktCart.addItem('shirt-1', 2);
const result = await mktCart.checkout(); // Creates separate links per vendor

Store React Hooks

import { useProducts, useCart } from '@rotateprotocol/sdk/hooks';

const { products } = useProducts(store);
const { addItem, totals, checkout } = useCart(store);

Fees

| Fee | Rate | |-----|------| | Protocol | 3% (fixed) | | Platform | 0–6% (you set it) | | Split | 50/50 buyer/seller | | Tips | 100% to merchant |


API Reference

RotateSDK Methods

| Method | Description | |--------|-------------| | getPaymentLink(id) | Get link status | | isLinkPaid(id) | Check if paid | | waitForPayment(id, timeout) | Wait for payment | | createPlatform(params) | Create platform | | createMerchant(params) | Create merchant | | createLinkUsd(params) | Create USD link | | createLinkSol(params) | Create SOL link | | createLinkToken(params) | Create USDC/USDT link | | payLinkSol(params) | Pay SOL link | | payLinkToken(params) | Pay token link | | payLinkUsdSol(params) | Pay USD link with SOL | | payLinkUsdToken(params) | Pay USD link with USDC/USDT | | cancelLink(linkId, merchantId) | Cancel pending link | | getPaymentUrl(id) | Get checkout URL | | getSolPrice() | Get SOL/USD price | | calculateFees(amount, platformFeeBps) | Calculate fee breakdown |

ID System

| Entity | Format | Example | |--------|--------|---------| | Platform | 7-digit sequential | #1000000 | | Merchant | 7-digit sequential | #1000000 | | Payment Link | Sequential | #1, #2, #3 |


Development & Testing

Prerequisites

| Tool | Version | Install | |------|---------|---------| | Node.js | 20+ | nodejs.org | | Solana CLI | 2.3.5 | sh -c "$(curl -sSfL https://release.anza.xyz/v2.3.5/install)" | | Anchor CLI | 0.32.1 | cargo install --git https://github.com/coral-xyz/anchor avm && avm install 0.32.1 && avm use 0.32.1 | | Rust | stable | rustup update stable |

Running SDK Tests

cd sdk
npm install
npm test          # Unit tests (no validator needed)

Running Integration Tests (Local Validator)

Integration tests automatically detect a local validator. To start one:

# Terminal 1: Start local validator
solana-test-validator

# Terminal 2: Run tests (integration tests will connect to localhost:8899)
cd sdk
npm test

If no local validator is running, integration tests fall back to devnet.

Running Anchor Tests

cd solana
yarn install
anchor test       # Builds, deploys to localnet, and runs tests

Environment Variables

Create a .env file in the SDK directory for custom configuration:

# Custom RPC endpoint (optional, defaults to localhost:8899 for tests)
RPC_URL=http://127.0.0.1:8899

License

MIT