@maithinh/paymaster-sdk
v1.1.2
Published
Paymaster SDK for Solana
Readme
Paymaster SDK
TypeScript SDK for interacting with Paymaster Server on Solana blockchain. Simplifies transaction processing with automatic fee handling and server-side transaction modification.
Features
- ✅ Health Check - Verify Paymaster Server is online
- ✅ Token Price Fetching - Get real-time token prices and decimals
- ✅ Swap Fee Integration - Automatically add swap fees to transactions
- ✅ VersionedTransaction Support - Full support for V0 messages and VersionedTransaction
- ✅ Server-Side Signing - Server handles transaction signing with MASTER_WALLET
- ✅ Full TypeScript Support - Complete type definitions for all APIs
- ✅ ESM Module Support - Native ES Module support
- ✅ Comprehensive Error Handling - Detailed error messages and codes
Installation
npm install paymaster-sdkOr from git:
npm install github:Harmori-Finance/paymaster-sdkPrerequisites
- Node.js: >= 18
- Solana Web3.js: ^1.98.4
- @solana/spl-token: ^0.4.13
- @coral-xyz/anchor: ^0.31.1
Quick Start
1. Initialize SDK
import { PaymasterSDK } from 'paymaster-sdk';
const sdk = new PaymasterSDK({
baseUrl: 'http://localhost:8234',
timeout: 30000, // optional, default 30s
});2. Check Server Health
const isHealthy = await sdk.healthCheck();
console.log('Server is healthy:', isHealthy);3. Get Token Price
const priceInfo = await sdk.getTokenPrice('EPjFWaLb3odcccccccccccccccccccccccccccccccc');
console.log('Token Price:', priceInfo.price);
console.log('Token Decimals:', priceInfo.decimals);4. Add Swap Fee to Transaction
Option A: Regular Transaction
// Create and prepare transaction
const tx = new Transaction();
tx.add(/* your instruction here */);
tx.feePayer = user.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
// Serialize WITHOUT signing
const serialized = tx.serialize({ requireAllSignatures: false }).toString('base64');
// Send to Paymaster server
const result = await sdk.swapFee({
base64Tx: serialized,
token: 'EPjFWaLb3odcccccccccccccccccccccccccccccccc',
userAddress: user.publicKey.toString(),
});
// Parse modified transaction (already signed by MASTER_WALLET)
const modifiedTx = Transaction.from(Buffer.from(result.base64_tx, 'base64'));
modifiedTx.partialSign(user);
// Send to blockchain
const txid = await connection.sendRawTransaction(modifiedTx.serialize());Option B: VersionedTransaction (V0)
import { VersionedTransaction, TransactionMessage } from '@solana/web3.js';
// Create V0 message
const message = new TransactionMessage({
payerKey: user.publicKey,
recentBlockhash: (await connection.getLatestBlockhash('finalized')).blockhash,
instructions: [/* your instructions */],
}).compileToV0Message();
// Create VersionedTransaction
const versionedTx = new VersionedTransaction(message);
// Serialize to base64
const serialized = Buffer.from(versionedTx.serialize()).toString('base64');
// Send to Paymaster server
const result = await sdk.versionedSwapFee({
base64Tx: serialized,
token: 'EPjFWaLb3odcccccccccccccccccccccccccccccccc',
userAddress: user.publicKey.toString(),
});
// Deserialize and sign modified VersionedTransaction
const modifiedTx = VersionedTransaction.deserialize(
new Uint8Array(Buffer.from(result.base64_tx, 'base64'))
);
modifiedTx.sign([user]);
// Send to blockchain
const txid = await connection.sendRawTransaction(modifiedTx.serialize());API Reference
PaymasterSDK
Constructor
new PaymasterSDK(config: PaymasterSDKConfig)Parameters:
config.baseUrl(string): Base URL of Paymaster Serverconfig.timeout(number, optional): Request timeout in milliseconds (default: 30000)
Methods
healthCheck(): Promise<boolean>
Check if the Paymaster Server is running and healthy.
Returns: true if server is healthy, false otherwise
Example:
const isHealthy = await sdk.healthCheck();getTokenPrice(tokenAddress: string): Promise<TokenPriceInfo>
Get the price and decimals for a specific token.
Parameters:
tokenAddress(string): The token mint address
Returns:
interface TokenPriceInfo {
price: number;
decimals: number;
}Example:
const priceInfo = await sdk.getTokenPrice('EPjFWaLb3od...');
console.log(`1 token = ${priceInfo.price} USDC`);swapFee(payload: SwapFeePayload): Promise<SwapFeeResponse>
Add swap fee instruction to a regular Transaction. The server will handle the fee addition and sign the transaction with MASTER_WALLET.
Important Flow:
- Client creates transaction and serializes to base64 (WITHOUT signing)
- Client sends base64 to server via
swapFee() - Server:
- Deserializes transaction
- Adds swap fee instruction
- Sets
feePayer = MASTER_WALLET - Signs with
MASTER_WALLET.partialSign() - Returns modified base64Tx
- Client receives modified transaction (already has MASTER_WALLET's signature)
- Client deserializes and signs with user's keypair using
partialSign() - Now transaction has both MASTER_WALLET and user signatures
- Client sends to blockchain
Parameters:
interface SwapFeePayload {
base64Tx: string; // Base64 encoded transaction (unsigned)
token: string; // Token mint address
userAddress: string; // User's Solana wallet address
}Returns:
interface SwapFeeResponse {
base64_tx: string; // Modified transaction (signed by MASTER_WALLET)
}versionedSwapFee(payload: VersionedSwapFeePayload): Promise<SwapFeeResponse>
Add swap fee instruction to a VersionedTransaction (V0 message). The server will handle the fee addition and sign with MASTER_WALLET.
Important Flow:
- Client creates VersionedTransaction (V0 message) and serializes to base64
- Client sends base64 to server via
versionedSwapFee() - Server:
- Deserializes VersionedTransaction
- Decodes V0 message
- Adds swap fee instructions
- Sets
feePayer = MASTER_WALLET - Signs with MASTER_WALLET
- Returns modified base64Tx (VersionedTransaction format)
- Client receives modified VersionedTransaction (already has MASTER_WALLET's signature)
- Client deserializes and signs with user's keypair using
sign() - Now VersionedTransaction has both MASTER_WALLET and user signatures
- Client sends to blockchain
Parameters:
interface VersionedSwapFeePayload {
base64Tx: string; // Base64 encoded VersionedTransaction
token: string; // Token mint address
userAddress: string; // User's Solana wallet address
}Returns:
interface SwapFeeResponse {
base64_tx: string; // Modified VersionedTransaction (signed by MASTER_WALLET)
}Differences from Regular Transaction:
- Use
VersionedTransaction.deserialize()instead ofTransaction.from() - Use
tx.sign([user])instead oftx.partialSign(user) - Supports Address Lookup Tables (ALTs) for lower fees
- Required for complex transactions with many accounts
Error Handling
The SDK throws PaymasterSDKError for API errors:
import { PaymasterSDKError } from 'paymaster-sdk';
try {
const priceInfo = await sdk.getTokenPrice(tokenAddress);
} catch (error) {
if (error instanceof PaymasterSDKError) {
console.error('Error Code:', error.code);
console.error('Status:', error.status);
console.error('Message:', error.message);
}
}Main Exports
The SDK exports the following items:
// Main client
export { PaymasterSDK } from 'paymaster-sdk';
// Error class and utilities
export { PaymasterSDKError, handleResponse, makeRequest } from 'paymaster-sdk';
// Type definitions
export type {
ApiResponse,
TokenPriceInfo,
SwapFeeResponse,
SwapFeePayload,
VersionedSwapFeePayload,
PaymasterSDKConfig,
ApiError,
} from 'paymaster-sdk';Type Definitions
/**
* SDK Configuration
*/
interface PaymasterSDKConfig {
baseUrl: string; // URL of Paymaster Server
timeout?: number; // Request timeout (ms), default: 30000
}
/**
* Token price response
*/
interface TokenPriceInfo {
price: number; // Token price
decimals: number; // Token decimals
}
/**
* Swap fee request payload
*/
interface SwapFeePayload {
base64Tx: string; // Base64 encoded transaction (unsigned)
token: string; // Token mint address
userAddress: string; // User's Solana wallet address
}
/**
* Versioned swap fee request payload (VersionedTransaction)
*/
interface VersionedSwapFeePayload {
base64Tx: string; // Base64 encoded VersionedTransaction
token: string; // Token mint address
userAddress: string; // User's Solana wallet address
}
/**
* Swap fee response
*/
interface SwapFeeResponse {
base64_tx: string; // Modified transaction (signed by MASTER_WALLET)
}
/**
* API Error response
*/
interface ApiError {
message: string; // Error message
code?: string; // Error code
status?: number; // HTTP status code
}
/**
* Generic API response
*/
interface ApiResponse<T = any> {
success: boolean; // Whether request was successful
data?: T; // Response data
error?: {
message: string;
code?: string;
};
}Building from Source
Prerequisites
- TypeScript 5.9+
- Node.js 18+
Build Commands
# Install dependencies
npm install
# Build TypeScript to JavaScript
npm run build
# Run development example
npm run dev:loader
# Check build output
ls -la dist/Project Structure
paymaster-sdk/
├── src/
│ ├── index.ts # Main entry point (exports)
│ ├── client.ts # PaymasterSDK class
│ │ ├── swapFee() # Regular Transaction
│ │ ├── versionedSwapFee() # VersionedTransaction (V0)
│ │ ├── getTokenPrice()
│ │ └── healthCheck()
│ ├── types.ts # TypeScript interfaces
│ └── utils.ts # Utilities & error handling
├── examples/
│ ├── example.ts # Regular Transaction example
│ └── examples-versioned.ts # VersionedTransaction example
├── dist/ # Compiled JavaScript (generated after build)
├── package.json # Project config & scripts
├── tsconfig.json # TypeScript config
└── README.md # This fileBuild Output
After running npm run build, the dist/ folder contains:
index.jsandindex.d.ts- Main entry pointclient.jsandclient.d.ts- SDK clienttypes.jsandtypes.d.ts- Type definitionsutils.jsandutils.d.ts- Utilities- Source maps (
.js.mapand.d.ts.map) for debugging
Complete Examples
Example 1: Regular Transaction
This example demonstrates:
- Creating a transaction with ATA creation (if needed)
- Token transfer instruction
- Health check
- Token price fetching
- Swap fee addition
- Transaction signing and sending
import {
createAssociatedTokenAccountInstruction,
createTransferInstruction,
getAssociatedTokenAddress,
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import { Connection, Keypair, PublicKey, Transaction, SystemProgram } from '@solana/web3.js';
import { PaymasterSDK } from 'paymaster-sdk';
import 'dotenv/config';
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
async function main() {
// Setup
const SECRET_KEY = process.env.SECRET_KEY ?? '';
const connection = new Connection('https://api.devnet.solana.com');
const mintUSDC = new PublicKey('USDCoctVLVnvTXBEuP9s8hntucdJokbo17RwHuNXemT');
const user = Keypair.fromSecretKey(bs58.decode(SECRET_KEY));
const recipient = new PublicKey('GS69bzeoeQTB2TspXt1cvGhqDigLGvK6AgcAGAxaYraW');
// Get token accounts
const fromAccount = await getAssociatedTokenAddress(mintUSDC, user.publicKey);
const toAccount = await getAssociatedTokenAddress(mintUSDC, recipient);
const tx = new Transaction();
// Check if recipient has ATA, create if needed
const recipientATAInfo = await connection.getAccountInfo(toAccount);
if (!recipientATAInfo) {
const createAtaIx = createAssociatedTokenAccountInstruction(
user.publicKey, // payer
toAccount, // ATA address
recipient, // owner
mintUSDC, // mint
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);
tx.add(createAtaIx);
console.log('Added: Create ATA for recipient');
}
// Add transfer instruction
const transferIx = createTransferInstruction(
fromAccount,
toAccount,
user.publicKey,
10 * 10 ** 6 // 10 USDC
);
tx.add(transferIx);
// Set temporary feePayer (server will replace with MASTER_WALLET)
tx.feePayer = user.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash('finalized')).blockhash;
// Serialize WITHOUT signing
const serialized = tx.serialize({ requireAllSignatures: false }).toString('base64');
// Initialize SDK
const sdk = new PaymasterSDK({
baseUrl: 'http://localhost:8234',
timeout: 30000,
});
try {
// Health check
console.log('Checking server health...');
const isHealthy = await sdk.healthCheck();
console.log('Server is healthy:', isHealthy);
// Get token price
console.log('\nGetting token price...');
const priceInfo = await sdk.getTokenPrice(mintUSDC.toString());
console.log('Token Price:', priceInfo.price);
// Add swap fee to transaction
console.log('\nAdding swap fee to transaction...');
const swapFeeResult = await sdk.swapFee({
base64Tx: serialized,
token: mintUSDC.toString(),
userAddress: user.publicKey.toString(),
});
// Parse modified transaction (already signed by MASTER_WALLET)
const transaction = Transaction.from(Buffer.from(swapFeeResult.base64_tx, 'base64'));
// Sign with user's keypair
transaction.partialSign(user);
// Send to blockchain
console.log('\nSending transaction...');
const serializedTx = transaction.serialize();
const txid = await connection.sendRawTransaction(serializedTx);
console.log("TX Hash:", txid);
// Confirm transaction
const confirmation = await connection.confirmTransaction(txid);
console.log("Confirmation:", confirmation);
} catch (error: any) {
console.error('Error:', error.message);
}
}
main().catch(console.error);Example 2: VersionedTransaction (V0)
This example demonstrates:
- Creating VersionedTransaction with V0 message
- Support for Address Lookup Tables (ALTs)
- Lower transaction size for complex transactions
- Swap fee addition with VersionedTransaction
- Signing and sending
import {
Connection,
Keypair,
PublicKey,
VersionedTransaction,
TransactionMessage,
} from '@solana/web3.js';
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
createTransferInstruction,
getAssociatedTokenAddress,
TOKEN_PROGRAM_ID
} from '@solana/spl-token';
import { PaymasterSDK } from 'paymaster-sdk';
import 'dotenv/config';
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
async function testVersionedTransaction() {
const SECRET_KEY = process.env.SECRET_KEY ?? '';
const connection = new Connection('https://api.devnet.solana.com');
const mintUSDC = new PublicKey('USDCoctVLVnvTXBEuP9s8hntucdJokbo17RwHuNXemT');
const user = Keypair.fromSecretKey(bs58.decode(SECRET_KEY));
const recipient = new PublicKey('2fn3dJEUADumJBriz8nJfv2H5Kk9ejj5h5YwkATarGHY');
console.log('=== VersionedTransaction Example ===\n');
try {
// Get token accounts
const fromAccount = await getAssociatedTokenAddress(mintUSDC, user.publicKey);
const toAccount = await getAssociatedTokenAddress(mintUSDC, recipient);
const instructions = [];
// Check if recipient has ATA
const recipientATAInfo = await connection.getAccountInfo(toAccount);
if (!recipientATAInfo) {
const createAtaIx = createAssociatedTokenAccountInstruction(
user.publicKey,
toAccount,
recipient,
mintUSDC,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);
instructions.push(createAtaIx);
console.log('Added: Create ATA for recipient');
}
// Add transfer instruction
const transferIx = createTransferInstruction(
fromAccount,
toAccount,
user.publicKey,
10 * 10 ** 6 // 10 USDC
);
instructions.push(transferIx);
// Get blockhash for message
const { blockhash } = await connection.getLatestBlockhash('finalized');
// Create VersionedTransaction with V0 message
const message = new TransactionMessage({
payerKey: user.publicKey,
recentBlockhash: blockhash,
instructions: instructions,
}).compileToV0Message();
const versionedTx = new VersionedTransaction(message);
// Serialize to base64
const serialized = Buffer.from(versionedTx.serialize()).toString('base64');
console.log('✓ Created VersionedTransaction');
// Initialize SDK
const sdk = new PaymasterSDK({
baseUrl: 'http://localhost:8234',
timeout: 30000,
});
// Health check
console.log('\n=== Server Health ===');
const isHealthy = await sdk.healthCheck();
console.log('✓ Server is healthy:', isHealthy);
// Get token price
console.log('\n=== Token Price ===');
const priceInfo = await sdk.getTokenPrice(mintUSDC.toString());
console.log('✓ Token Price:', priceInfo.price);
// Add swap fee to VersionedTransaction
console.log('\n=== Add Swap Fee (VersionedTransaction) ===');
const swapFeeResult = await sdk.versionedSwapFee({
base64Tx: serialized,
token: mintUSDC.toString(),
userAddress: user.publicKey.toString(),
});
console.log('✓ Modified VersionedTransaction received from server');
// Deserialize and sign
console.log('\n=== Parse and Sign ===');
const resultTx = VersionedTransaction.deserialize(
new Uint8Array(Buffer.from(swapFeeResult.base64_tx, 'base64'))
);
console.log('✓ Deserialized VersionedTransaction');
// Sign with user keypair
resultTx.sign([user]);
console.log('✓ Signed with user keypair');
// Send transaction
console.log('\n=== Send Transaction ===');
try {
const txid = await connection.sendRawTransaction(resultTx.serialize());
console.log('✓ TX Hash:', txid);
const confirmation = await connection.confirmTransaction(txid);
console.log('✓ Confirmation:', confirmation);
} catch (error: any) {
console.warn('⚠️ Warning: Could not send transaction:', error.message);
console.log('Transaction was modified successfully by server');
}
console.log('\n✅ All tests passed!');
} catch (error: any) {
console.error('❌ Error:', error.message);
}
}
testVersionedTransaction().catch(console.error);Run the examples:
# Development mode (with hot reload)
npm run dev:loader
# Build first
npm run build
# Then run with Node
node --loader ts-node/esm examples/example.ts # Regular Transaction
node --loader ts-node/esm examples/examples-versioned.ts # VersionedTransactionNPM Scripts
npm run build # Build TypeScript to dist/
npm run dev:loader # Run examples/example.ts with ts-node ESM loaderPackage Configuration
package.json exports:
{
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts"
}Environment Variables
Create a .env file in your project root for configuration:
# Paymaster Server
PAYMASTER_URL=http://localhost:8234
# Solana RPC Endpoint
SOLANA_RPC_URL=https://api.devnet.solana.com
# Your wallet secret key (base58 encoded)
SECRET_KEY=<your-base58-encoded-keypair>Using in code:
import 'dotenv/config';
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
const sdk = new PaymasterSDK({
baseUrl: process.env.PAYMASTER_URL || 'http://localhost:8234',
timeout: 30000,
});
const connection = new Connection(
process.env.SOLANA_RPC_URL || 'https://api.devnet.solana.com'
);
const user = Keypair.fromSecretKey(
bs58.decode(process.env.SECRET_KEY || '')
);Common Patterns
When to use Regular Transaction vs VersionedTransaction?
| Feature | Regular Tx | VersionedTx | |---------|-----------|-------------| | Simple transfers | ✅ Simpler | ⚠️ Overkill | | Few accounts | ✅ Better | ⚠️ Overkill | | ALT support | ❌ No | ✅ Yes | | Complex txs | ⚠️ May fail | ✅ Recommended | | Many accounts | ❌ Limited | ✅ Better | | Lower fees | ⚠️ Higher | ✅ Lower | | Compatibility | ✅ Wider | ⚠️ Needs v0 support |
Choose Regular Transaction if:
- Simple token transfers or swaps
- 3-5 accounts max
- Quick and simple transactions
- Don't need advanced features
Choose VersionedTransaction if:
- Complex transactions with many accounts
- Need to use Address Lookup Tables (ALTs)
- Want to minimize transaction size
- Need lower fees for complex operations
- Building advanced dApps
Creating ATA if not exists
import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from '@solana/spl-token';
const ataAddress = await getAssociatedTokenAddress(mint, owner);
const ataInfo = await connection.getAccountInfo(ataAddress);
if (!ataInfo) {
// Create ATA instruction
const ix = createAssociatedTokenAccountInstruction(
feePayer,
ataAddress,
owner,
mint
);
tx.add(ix);
}Getting token account balance
const balance = await connection.getTokenAccountBalance(tokenAccount);
console.log(`Balance: ${balance.value.amount}`);
console.log(`Decimals: ${balance.value.decimals}`);Decoding secret key
import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes';
const secretKey = process.env.SECRET_KEY!;
const keypair = Keypair.fromSecretKey(bs58.decode(secretKey));Regular Transaction vs VersionedTransaction signing
// ✅ Regular Transaction - use partialSign()
const tx = Transaction.from(Buffer.from(base64, 'base64'));
tx.partialSign(user); // Only adds user signature
await connection.sendRawTransaction(tx.serialize());
// ✅ VersionedTransaction - use sign()
const vTx = VersionedTransaction.deserialize(
new Uint8Array(Buffer.from(base64, 'base64'))
);
vTx.sign([user]); // Signs transaction, replaces signatures
await connection.sendRawTransaction(vTx.serialize());Troubleshooting
Import errors with .js extension
Error: Cannot find module './client'
Solution: Ensure all TypeScript imports have .js extension:
// ✅ Correct
import { PaymasterSDK } from './client.js';
// ❌ Wrong
import { PaymasterSDK } from './client';This is required for ESM module resolution in Node.js.
Transaction Signing Issues
Problem: Transaction fails because you signed it before sending to Paymaster server.
Solution: Never sign before sending to server:
// ✅ CORRECT: Don't sign before sending
const serialized = tx.serialize({ requireAllSignatures: false }).toString('base64');
const result = await sdk.swapFee({ base64Tx: serialized, ... });
// Server returns transaction signed by MASTER_WALLET
const modifiedTx = Transaction.from(Buffer.from(result.base64_tx, 'base64'));
// Then sign with your keypair
modifiedTx.partialSign(user);
// Now send
await connection.sendRawTransaction(modifiedTx.serialize());"Blockhash not found" error
Problem: Error: Simulation failed: Blockhash not found
Reason: Solana blockhash expires after ~2 minutes. If server takes time processing, blockhash may expire.
Solution: Get fresh blockhash before sending:
// Get blockhash BEFORE creating transaction
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('finalized');
tx.recentBlockhash = blockhash;Connection refused to Paymaster Server
Problem: Error: connect ECONNREFUSED 127.0.0.1:8234
Solution: Ensure server is running:
# Check if server is running
curl http://localhost:8234/
# Verify healthCheck
const isHealthy = await sdk.healthCheck();
if (!isHealthy) {
console.error('Cannot reach Paymaster server');
}Build/Compilation errors
Problem: TypeScript compilation errors after changes
Solution: Rebuild the project:
npm run buildAnd ensure:
- TypeScript 5.9+ is installed:
npm list typescript tsconfig.jsonhas correct settings- All source files are in
src/directory
"Blockhash not found" error
- This is normal when transaction blockhash expires (~2 minutes)
- Get a fresh blockhash just before sending the transaction:
tx.recentBlockhash = (await connection.getLatestBlockhash('finalized')).blockhash;
Connection errors to Paymaster Server
- Ensure server is running at
baseUrl - Check CORS configuration on server
- Verify network connectivity
- Example debug:
const isHealthy = await sdk.healthCheck(); if (!isHealthy) { console.error('Cannot connect to Paymaster server'); }
TypeScript compilation errors
- Ensure TypeScript 5.9+ is installed
- Check
tsconfig.jsonhas correct settings - Run
npm run buildto verify compilation - Use
npm run dev:loaderfor development with automatic recompilation
Support & Documentation
API Docs
- Full API documentation is available in the API Reference section above
Example Code
- See
examples/example.tsfor a complete working example - Run it with:
npm run dev:loader
Issues
For bugs and feature requests, please open an issue on GitHub: Harmori-Finance/paymaster-sdk
License
ISC
Contributing
Contributions are welcome! Please ensure:
- Code follows TypeScript strict mode
- All types are properly defined
- Error handling is comprehensive
- Examples are updated if adding new features
- Run
npm run buildto verify compilation
Development workflow
# Install dependencies
npm install
# Make changes in src/
# Edit example in examples/example.ts
# Test with dev:loader
npm run dev:loader
# Build when ready
npm run build
# Commit changes
git add .
git commit -m "Description of changes"Paymaster SDK | Solana | TypeScript
Last Updated: November 11, 2025
Version: 1.0.0
Maintained by: Harmori Finance
