@kreyon/spi_library
v0.1.6
Published
Solana Payment Integration library with loyalty rewards, memberships, and dynamic NFT generation
Downloads
73
Maintainers
Readme
@kreyon/spi_library
A comprehensive Solana Payment Integration library with built-in loyalty rewards, membership management, and dynamic NFT generation. Built on top of Solana Pay and Anchor framework.
🌟 Features
- 💳 Solana Pay Integration - Generate QR codes and handle payments seamlessly
- 🎁 Loyalty Rewards System - Multiple reward algorithms to incentivize customer engagement
- 👑 Membership Management - Monthly and yearly subscription plans
- 🖼️ Dynamic NFT Generation - Auto-generated NFT membership cards with user stats
- 🔒 Merkle Tree Whitelisting - Built-in support for user verification
- 📊 Transaction Analytics - Track spending, cashback, and loyalty points
- 🎯 Flexible Discount System - Apply custom discounts to transactions
📦 Installation
npm install @kreyon/spi_library
# or
yarn add @kreyon/spi_library
# or
bun add @kreyon/spi_libraryPeer Dependencies
Make sure you have the following peer dependencies installed:
npm install @coral-xyz/anchor @solana/pay @solana/web3.js sharp🚀 Quick Start
For Next.js Applications
The library provides separate exports for client and server components:
// Client Component
import { SpiClient } from "@kreyon/spi_library/client";
// Server Component / API Routes
import { SpiServer } from "@kreyon/spi_library/server";For Other Frameworks
import { SpiClient, SpiServer } from "@kreyon/spi_library";📚 API Documentation
SpiServer (Server-Side)
The SpiServer class handles all server-side operations including payment processing, membership management, and NFT generation.
Constructor
const spiServer = new SpiServer(
keypair: Keypair, // Your merchant wallet keypair
rpc_url: string, // Solana RPC endpoint URL
store_name: string, // Your store/business name
nft_art?: string // Optional: Custom NFT artwork URL
);Example:
import { SpiServer } from "@kreyon/spi_library/server";
import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";
// Initialize your keypair (from environment variable)
const keypair = Keypair.fromSecretKey(
bs58.decode(process.env.MERCHANT_PRIVATE_KEY!)
);
const spiServer = new SpiServer(
keypair,
"https://api.devnet.solana.com",
"My Awesome Store",
"https://example.com/custom-nft-art.png" // Optional
);Methods
getTransferReq()
Returns the basic transfer request metadata for Solana Pay.
const metadata = spiServer.getTransferReq();
// Returns: { label: "My Awesome Store", icon: "..." }transfer()
Creates a Solana Pay transaction for payment with rewards.
async transfer(
referenceKey: PublicKey, // Unique reference for this transaction
amount: number, // Amount in lamports
userKey: PublicKey, // Customer's wallet address
discount: number, // Discount percentage (0-100)
rewardAlgo: "SPI_ALGO_1" | "SPI_ALGO_2" | "SPI_ALGO_3"
): Promise<{ transaction: string, message: string }>Example:
import { PublicKey, Keypair } from "@solana/web3.js";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
// Generate a unique reference for this transaction
const reference = Keypair.generate().publicKey;
const userWallet = new PublicKey("user_wallet_address_here");
const result = await spiServer.transfer(
reference,
0.5 * LAMPORTS_PER_SOL, // 0.5 SOL
userWallet,
10, // 10% discount
"SPI_ALGO_1" // Reward algorithm
);
// result.transaction contains base64 encoded transaction
// Send this to the client for signingprime_membership()
Creates a membership subscription transaction.
async prime_membership(
referenceKey: PublicKey,
userKey: PublicKey,
name: string, // User's name
validity: "MONTHLY" | "YEARLY"
): Promise<{ transaction: string, message: string }>Example:
const reference = Keypair.generate().publicKey;
const userWallet = new PublicKey("user_wallet_address");
const membership = await spiServer.prime_membership(
reference,
userWallet,
"John Doe",
"MONTHLY" // 0.1 SOL for monthly, 0.2 SOL for yearly
);
// Returns serialized transaction for client to signgetNftArt()
Generates a dynamic NFT image with user statistics.
async getNftArt(userKey: PublicKey): Promise<Buffer>Example:
const userWallet = new PublicKey("user_wallet_address");
const nftImageBuffer = await spiServer.getNftArt(userWallet);
// Use the buffer to create an NFT or serve as an image
// For Next.js API routes:
return new Response(nftImageBuffer, {
headers: { "Content-Type": "image/jpeg" }
});SpiClient (Client-Side)
The SpiClient class handles client-side operations like token creation, QR code generation, and payment confirmation.
Constructor
const spiClient = new SpiClient(
keypair: Keypair, // Client wallet keypair
rpc_url: string // Solana RPC endpoint
);Example:
import { SpiClient } from "@kreyon/spi_library/client";
import { Keypair } from "@solana/web3.js";
const wallet = Keypair.generate(); // Or use existing wallet
const spiClient = new SpiClient(
wallet,
"https://api.devnet.solana.com"
);Methods
create_token()
Creates a new SPL token.
async create_token(
name: string,
symbol: string,
metadata: string
): Promise<string> // Returns transaction signatureExample:
const txSignature = await spiClient.create_token(
"Kreyon Token",
"KRYN",
"https://arweave.net/token-metadata.json"
);
console.log(`Token created: https://solscan.io/tx/${txSignature}`);get_qr_code()
Generates a Solana Pay QR code.
get_qr_code(endpoint: string, size: number): QRCodeExample:
const qrCode = spiClient.get_qr_code(
"https://mystore.com/api/pay",
512 // QR code size in pixels
);
// In React:
// <img src={qrCode.toDataURL()} alt="Scan to pay" />confirm_payment()
Confirms a payment transaction using a reference key.
async confirm_payment(referenceKey: PublicKey): Promise<boolean>Example:
import { PublicKey } from "@solana/web3.js";
const reference = new PublicKey("reference_public_key");
const isConfirmed = await spiClient.confirm_payment(reference);
if (isConfirmed) {
console.log("Payment confirmed!");
// Update UI, grant access, etc.
}🎯 Reward Algorithms
The library includes three built-in reward algorithms:
SPI_ALGO_1 (Balanced)
- Base reward: 1% of transaction amount
- Loyalty bonus: Based on total transactions (1 + transactions/10,000)
- Spend bonus: Based on total spent (1 + total_spent/100,000)
- Best for: General retail, moderate engagement
SPI_ALGO_2 (Generous)
- Base reward: 2.5% of transaction amount
- Loyalty bonus: Based on total transactions (1 + transactions/5,000)
- Spend bonus: Based on total spent (1 + total_spent/50,000)
- Best for: High-value customers, premium stores
SPI_ALGO_3 (Conservative)
- Base reward: 0.25% of transaction amount
- Loyalty bonus: Based on total transactions (1 + transactions/20,000)
- Fraud control: Reduces rewards based on cashback ratio
- Best for: High-risk environments, fraud prevention
🛠️ Utility Functions
hexProofToAnchorFormat()
Converts hex proof array to Anchor-compatible format.
import { hexProofToAnchorFormat } from "@kreyon/spi_library/server";
const hexProof = ["0xabc123...", "0xdef456..."];
const anchorProof = hexProofToAnchorFormat(hexProof);anchorProofToHex()
Converts Anchor proof format back to hex strings.
import { anchorProofToHex } from "@kreyon/spi_library/server";
const hexProof = anchorProofToHex(anchorFormatProof);daysFromNow()
Returns UNIX timestamp for X days in the future.
import { daysFromNow } from "@kreyon/spi_library/server";
const thirtyDaysLater = daysFromNow(30);unixToShortDate()
Converts UNIX timestamp to readable date format.
import { unixToShortDate } from "@kreyon/spi_library/server";
const date = unixToShortDate(1704067200);
// Returns: "01 Jan 2024"bnToCleanNumber()
Converts Anchor BN (BigNumber) to regular number.
import { bnToCleanNumber } from "@kreyon/spi_library/server";
const cleanNumber = bnToCleanNumber(anchorBN);💡 Complete Examples
Next.js API Route (Payment Endpoint)
// app/api/pay/route.ts
import { SpiServer } from "@kreyon/spi_library/server";
import { Keypair, PublicKey, LAMPORTS_PER_SOL } from "@solana/web3.js";
import { NextRequest, NextResponse } from "next/server";
import bs58 from "bs58";
const spiServer = new SpiServer(
Keypair.fromSecretKey(bs58.decode(process.env.MERCHANT_PRIVATE_KEY!)),
process.env.RPC_URL!,
"My Store"
);
export async function POST(req: NextRequest) {
try {
const { account, amount, discount } = await req.json();
const reference = Keypair.generate().publicKey;
const userWallet = new PublicKey(account);
const result = await spiServer.transfer(
reference,
amount * LAMPORTS_PER_SOL,
userWallet,
discount || 0,
"SPI_ALGO_1"
);
return NextResponse.json({
transaction: result.transaction,
message: result.message,
reference: reference.toBase58()
});
} catch (error) {
return NextResponse.json(
{ error: "Payment processing failed" },
{ status: 500 }
);
}
}
export async function GET(req: NextRequest) {
return NextResponse.json(spiServer.getTransferReq());
}Next.js API Route (Membership)
// app/api/membership/route.ts
import { SpiServer } from "@kreyon/spi_library/server";
import { Keypair, PublicKey } from "@solana/web3.js";
import { NextRequest, NextResponse } from "next/server";
import bs58 from "bs58";
const spiServer = new SpiServer(
Keypair.fromSecretKey(bs58.decode(process.env.MERCHANT_PRIVATE_KEY!)),
process.env.RPC_URL!,
"My Store"
);
export async function POST(req: NextRequest) {
const { account, name, plan } = await req.json();
const reference = Keypair.generate().publicKey;
const userWallet = new PublicKey(account);
const result = await spiServer.prime_membership(
reference,
userWallet,
name,
plan // "MONTHLY" or "YEARLY"
);
return NextResponse.json({
transaction: result.transaction,
message: result.message
});
}Next.js API Route (Dynamic NFT)
// app/api/nft/[wallet]/route.ts
import { SpiServer } from "@kreyon/spi_library/server";
import { Keypair, PublicKey } from "@solana/web3.js";
import { NextRequest, NextResponse } from "next/server";
import bs58 from "bs58";
const spiServer = new SpiServer(
Keypair.fromSecretKey(bs58.decode(process.env.MERCHANT_PRIVATE_KEY!)),
process.env.RPC_URL!,
"My Store"
);
export async function GET(
req: NextRequest,
{ params }: { params: { wallet: string } }
) {
try {
const userWallet = new PublicKey(params.wallet);
const nftBuffer = await spiServer.getNftArt(userWallet);
return new Response(nftBuffer, {
headers: {
"Content-Type": "image/jpeg",
"Cache-Control": "public, max-age=60"
}
});
} catch (error) {
return NextResponse.json(
{ error: "Failed to generate NFT" },
{ status: 500 }
);
}
}React Component (Payment QR Code)
// components/PaymentQR.tsx
"use client";
import { SpiClient } from "@kreyon/spi_library/client";
import { useEffect, useState } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
export default function PaymentQR() {
const { publicKey } = useWallet();
const [qrCode, setQrCode] = useState<string>("");
useEffect(() => {
if (publicKey) {
const endpoint = `${window.location.origin}/api/pay?account=${publicKey.toBase58()}`;
// Note: SpiClient needs a keypair, but for QR generation only,
// you can create it without actual signing
const qr = createQR(endpoint, 512);
setQrCode(qr.toDataURL());
}
}, [publicKey]);
return qrCode ? (
<img src={qrCode} alt="Scan to pay with Solana" />
) : (
<p>Connect wallet to generate QR code</p>
);
}🔧 Environment Variables
Create a .env.local file in your project:
MERCHANT_PRIVATE_KEY=your_base58_encoded_private_key
RPC_URL=https://api.devnet.solana.com
NEXT_PUBLIC_RPC_URL=https://api.devnet.solana.com📋 TypeScript Support
The library is written in TypeScript and includes full type definitions.
import type {
Spi,
Keypair,
PublicKey,
Connection,
AnchorProvider,
Program
} from "@kreyon/spi_library";🏗️ Project Structure
spi_library/
├── client.ts # Client-side exports
├── server.ts # Server-side exports
├── index.ts # Combined exports
├── spi_client.ts # SpiClient class
├── spi_server.ts # SpiServer class
├── classes/
│ ├── client/ # Client-specific classes
│ └── server/ # Server-specific classes
│ ├── asa.ts # Account management
│ ├── nft.ts # NFT generation
│ └── transfer.ts # Payment processing
├── shared/
│ ├── algorithm.ts # Reward algorithms
│ ├── anchor.ts # Anchor setup
│ └── program/ # Solana program IDL
└── utils/
└── index.ts # Utility functions🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
- NPM Package: @kreyon/spi_library
- Homepage: https://spi.kreyon.in
- GitHub: https://github.com/krey-yon/spi_library
- Issues: Report a bug
📞 Support
For questions and support, please open an issue on GitHub or visit our homepage.
⚠️ Important Notes
- Security: Never expose your private keys in client-side code
- Network: Make sure to use the correct RPC endpoint (devnet/mainnet)
- Dependencies: Ensure all peer dependencies are installed
- Next.js: Use proper client/server imports to avoid build errors
- Testing: Always test on devnet before deploying to mainnet
🎓 Learn More
Made with ❤️ by Vikas
