@verxioprotocol/core
Version:
Opensource infrastructure powering on-chain loyalty across Solana with Metaplex Core
1,001 lines (820 loc) • 29.7 kB
Markdown
# Verxio Protocol
On-chain loyalty infrastructure for creating and managing loyalty programs on solana and SVM.
## Features
### Core Loyalty System
- **Create loyalty programs** with custom tiers and rewards
- **Issue loyalty passes as NFTs** with automatic metadata generation or custom metadata
- **Track user XP and tier progression** with automatic tier updates
- **Support for transferable loyalty passes** (with organization approval)
- **Built-in support for multiple networks** (Solana, Sonic)
- **Automatic tier progression** based on XP accumulation
- **Update loyalty program tiers and points per action** dynamically
- **Gift points to users** with custom actions and reasons
- **Comprehensive asset data and customer behavior tracking**
- **Flexible authority management** for loyalty programs and loyalty pass updates
### Communication & Messaging
- **Direct messaging** between program and pass holders
- **Program-wide broadcasts** with targeted delivery options
- **Message read status tracking** and analytics
- **Rich message metadata** with timestamps and sender information
### Advanced Transaction Composition
- **Instruction-based functions** for advanced transaction batching
- **Custom fee handling** and gas optimization
- **Transaction composition** with multiple operations
- **Built-in protocol fees** with transparent cost structure
### Complete Voucher Management System
- **Create, mint, validate, and redeem vouchers** with full lifecycle management
- **Voucher Collections** - Organize vouchers by merchant and type
- **Voucher Analytics** - Track redemption rates, usage patterns, and performance metrics
- **User Voucher Management** - Get user vouchers with filtering and sorting
- **Merchant Voucher Operations** - Bulk operations and merchant-specific analytics
- **Voucher Validation** - Comprehensive validation with expiry and usage tracking
- **Voucher Redemption** - Multi-type voucher redemption with value calculation
- **Voucher Expiry Management** - Extend or cancel vouchers with reason tracking
- **Merchant Identification** - Flexible merchant ID system for off-chain integration
### Supported Voucher Types
- **Percentage Off Vouchers** - Dynamic discounts based on purchase amount
- **Fixed Credit Vouchers** - Fixed value credits for any purchase
- **Free Item Vouchers** - Free items up to specified value
- **Buy One Get One Vouchers** - BOGO promotions with value limits
- **Custom Reward Vouchers** - Flexible reward structures
### Advanced Features
- **Irys Integration** - Automatic NFT image and metadata uploads
- **Comprehensive Test Suite** - Full coverage with 100+ test cases
- **Robust Error Handling** - Detailed validation and error messages
- **Type Safety** - Full TypeScript support with comprehensive types
- **Performance Optimized** - Efficient blockchain operations and data structures
## Installation
```bash
npm install @verxioprotocol/core
# or
yarn add @verxioprotocol/core
# or
pnpm add @verxioprotocol/core
```
## Quick Start
### Initialize Protocol
```typescript
import { initializeVerxio } from '@verxioprotocol/core'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { publicKey, keypairIdentity } from '@metaplex-foundation/umi'
// Create UMI instance (Solana & SVM supported)
const umi = createUmi('RPC_URL')
// Add Irys uploader for metadata/image uploads (Optional)
umi.use(irysUploader())
// Initialize program
const context = initializeVerxio(
umi,
publicKey('PROGRAM_AUTHORITY'), // Program authority public key
)
// Set Signer
context.umi.use(keypairIdentity('FEE_PAYER'))
```
### Create Your First Loyalty Program
```typescript
import { createLoyaltyProgram } from '@verxioprotocol/core'
const result = await createLoyaltyProgram(context, {
loyaltyProgramName: 'Coffee Brew Rewards',
metadataUri: 'https://arweave.net/...',
programAuthority: context.programAuthority,
metadata: {
organizationName: 'Coffee Brew', // Required
brandColor: '#FF5733', // Optional: for UI customization
},
tiers: [
{ name: 'Bronze', xpRequired: 500, rewards: ['2% cashback'] },
{ name: 'Silver', xpRequired: 1000, rewards: ['5% cashback'] },
{ name: 'Gold', xpRequired: 2000, rewards: ['10% cashback'] },
],
pointsPerAction: {
purchase: 100,
review: 50,
referral: 200,
},
})
console.log('Loyalty Program Created:', result.collection.publicKey)
```
## Two Approaches to Using Verxio Protocol
Verxio Protocol provides two complementary approaches for different use cases:
### 1. Direct Functions (Immediate Execution)
Traditional functions that execute transactions immediately - perfect for simple, single-operation use cases.
### 2. Instruction Functions (Advanced Composition)
Instruction-based functions that return `TransactionBuilder` objects for advanced transaction composition, batching, and custom fee handling.
## Direct Functions Usage
### Initialize Protocol
```typescript
import { initializeVerxio } from '@verxioprotocol/core'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { publicKey } from '@metaplex-foundation/umi'
// Create UMI instance (Solana & SVM supported)
const umi = createUmi('RPC_URL')
// Initialize program
const context = initializeVerxio(
umi,
publicKey('PROGRAM_AUTHORITY'), // Program authority public key
)
// Set Signer
context.umi.use(keypairIdentity('FEE_PAYER'))
```
### Create Loyalty Program
You can either:
- **Provide a pre-uploaded metadata URI** (no image upload needed), or
- **Provide an image buffer and filename** to auto-upload the image and generate metadata.
#### 1. Using a pre-uploaded metadata URI
```typescript
const result = await createLoyaltyProgram(context, {
loyaltyProgramName: 'Coffee Brew Rewards',
metadataUri: 'https://arweave.net/...', // Already uploaded metadata
programAuthority: context.programAuthority,
updateAuthority: generateSigner(context.umi), // Optional: Provide custom update authority
metadata: {
organizationName: 'Coffee Brew', // Required: Name of the host/organization
brandColor: '#FF5733', // Optional: Brand color for UI customization
},
tiers: [
{
name: 'Bronze',
xpRequired: 500,
rewards: ['2% cashback'],
},
{
name: 'Silver',
xpRequired: 1000,
rewards: ['5% cashback'],
},
],
pointsPerAction: {
purchase: 100,
review: 50,
},
})
console.log(result)
// {
// collection: KeypairSigner, // Collection signer
// signature: string, // Transaction signature
// programAuthority: KeypairSigner // Update authority for the loyalty program
// }
```
#### 2. Uploading an image and generating metadata
```typescript
const fs = require('fs')
const imageBuffer = fs.readFileSync('logo.png')
const result = await createLoyaltyProgram(context, {
loyaltyProgramName: 'Coffee Brew Rewards',
imageBuffer, // Buffer of your image
imageFilename: 'logo.png',
programAuthority: context.programAuthority,
updateAuthority: generateSigner(context.umi), // Optional: Provide custom update authority
metadata: {
organizationName: 'Coffee Brew', // Required: Name of the host/organization
brandColor: '#FF5733', // Optional: Brand color for UI customization
},
tiers: [
{
name: 'Bronze',
xpRequired: 500,
rewards: ['2% cashback'],
},
{
name: 'Silver',
xpRequired: 1000,
rewards: ['5% cashback'],
},
],
pointsPerAction: {
purchase: 100,
review: 50,
},
})
// The protocol will upload the image, generate metadata, and use the resulting URI
```
### Update Loyalty Program
```typescript
// Update points per action
const result = await updateLoyaltyProgram(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
programAuthority: context.programAuthority,
updateAuthority: programAuthority, // Required: Program authority from Loyalty Program creation
newPointsPerAction: {
purchase: 150, // Update existing action
referral: 200, // Add new action
},
})
// Update tiers
const result = await updateLoyaltyProgram(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
programAuthority: context.programAuthority,
updateAuthority: programAuthority, // Required: Program authority from Loyalty Program creation
newTiers: [
{ name: 'Grind', xpRequired: 0, rewards: ['nothing for you!'] }, // Grind tier must exist
{ name: 'Bronze', xpRequired: 400, rewards: ['free item'] }, // Update existing tier
{ name: 'Silver', xpRequired: 1000, rewards: ['5% cashback'] },
{ name: 'Gold', xpRequired: 2000, rewards: ['10% cashback'] },
{ name: 'Platinum', xpRequired: 5000, rewards: ['20% cashback'] }, // Add new tier
],
})
// Update both tiers and points per action
const result = await updateLoyaltyProgram(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
programAuthority: context.programAuthority,
updateAuthority: programAuthority, // Required: Program authority from Loyalty Program creation
newTiers: [
{ name: 'Grind', xpRequired: 0, rewards: ['nothing for you!'] },
{ name: 'Bronze', xpRequired: 400, rewards: ['free item'] },
{ name: 'Silver', xpRequired: 1000, rewards: ['5% cashback'] },
{ name: 'Gold', xpRequired: 2000, rewards: ['10% cashback'] },
],
newPointsPerAction: {
purchase: 150,
referral: 200,
},
})
console.log(result)
// {
// signature: string // Transaction signature
// }
```
### Issue Loyalty Pass
You can either:
- **Provide a pre-uploaded metadata URI** (no image upload needed), or
- **Provide an image buffer and filename** to auto-upload the image and generate metadata.
#### 1. Using a pre-uploaded metadata URI
```typescript
const result = await issueLoyaltyPass(context, {
collectionAddress: context.collectionAddress,
recipient: publicKey('RECIPIENT_ADDRESS'),
passName: 'Coffee Rewards Pass',
passMetadataUri: 'https://arweave.net/...', // Already uploaded metadata
assetSigner: generateSigner(context.umi), // Optional: Provide a signer for the pass
updateAuthority: programAuthority, // Required: Program authority of the Loyalty Program
organizationName: 'Coffee Brew',
})
console.log(result)
// {
// asset: KeypairSigner, // Pass signer
// signature: string // Transaction signature
// }
```
#### 2. Uploading an image and generating metadata
```typescript
const imageBuffer = fs.readFileSync('pass.png')
const result = await issueLoyaltyPass(context, {
collectionAddress: context.collectionAddress,
recipient: publicKey('RECIPIENT_ADDRESS'),
passName: 'Coffee Rewards Pass',
imageBuffer, // Buffer of your image
imageFilename: 'pass.png',
updateAuthority: programAuthority, // Required: Program authority of the Loyalty Program
organizationName: 'Coffee Brew',
})
// The protocol will upload the image, generate metadata, and use the resulting URI
```
### Award Points
```typescript
const result = await awardLoyaltyPoints(context, {
passAddress: publicKey('PASS_ADDRESS'),
action: 'purchase',
signer: programAuthority, // Required: Program authority of the Loyalty Program
multiplier: 1, // Optional: Point multiplier (default: 1)
})
console.log(result)
// {
// points: number, // New total points
// signature: string // Transaction signature
// newTier: LoyaltyProgramTier // New tier if updated
// }
```
### Revoke Points
```typescript
const result = await revokeLoyaltyPoints(context, {
passAddress: publicKey('PASS_ADDRESS'),
pointsToRevoke: 50,
signer: programAuthority, // Required: Program authority of the Loyalty Program
})
console.log(result)
// {
// points: number, // New total points after reduction
// signature: string // Transaction signature
// newTier: LoyaltyProgramTier // New tier if updated
// }
```
### Gift Points
```typescript
const result = await giftLoyaltyPoints(context, {
passAddress: publicKey('PASS_ADDRESS'),
pointsToGift: 100,
signer: updateAuthority, // Required: Program authority of the Loyalty Program
action: 'bonus', // Reason for gifting points
})
console.log(result)
// {
// points: number, // New total points
// signature: string // Transaction signature
// newTier: LoyaltyProgramTier // New tier if updated
// }
```
### Get Asset Data
```typescript
const assetData = await getAssetData(context, publicKey('PASS_ADDRESS'))
console.log(assetData)
// {
// xp: number, // Current XP points
// lastAction: string | null, // Last action performed
// actionHistory: Array<{ // History of actions
// type: string,
// points: number,
// timestamp: number,
// newTotal: number
// }>,
// currentTier: string, // Current tier name
// tierUpdatedAt: number, // Timestamp of last tier update
// rewards: string[], // Available rewards
// name: string, // Asset name
// uri: string, // Asset metadata URI
// owner: string, // Asset owner address
// pass: string, // Pass public key
// metadata: { // Program metadata
// organizationName: string, // Required: Name of the host/organization
// brandColor?: string // Optional: Brand color for UI customization
// },
// rewardTiers: Array<{ // All available reward tiers
// name: string,
// xpRequired: number,
// rewards: string[]
// }>
// }
```
### Get Program Details
```typescript
const programDetails = await getProgramDetails(context)
console.log(programDetails)
// {
// name: string,
// uri: string,
// collectionAddress: string,
// updateAuthority: string,
// numMinted: number,
// creator: string,
// tiers: Array<{
// name: string,
// xpRequired: number,
// rewards: string[]
// }>,
// pointsPerAction: Record<string, number>,
// metadata: {
// organizationName: string, // Required: Name of the host/organization
// brandColor?: string // Optional: Brand color for UI customization
// }
// }
```
### Get Wallet Loyalty Passes
```typescript
const passes = await getWalletLoyaltyPasses(context, publicKey('WALLET_ADDRESS'))
console.log(passes)
// Array<{
// publicKey: string,
// name: string,
// uri: string,
// owner: string
// }>
```
### Get Program Tiers
```typescript
const tiers = await getProgramTiers(context)
console.log(tiers)
// Array<{
// name: string,
// xpRequired: number,
// rewards: string[]
// }>
```
### Get Points Per Action
```typescript
const pointsPerAction = await getPointsPerAction(context)
console.log(pointsPerAction)
// Record<string, number> // Action name to points mapping
```
### Approve Transfer
```typescript
await approveTransfer(context, {
passAddress: publicKey('PASS_ADDRESS'),
toAddress: publicKey('NEW_OWNER_ADDRESS'),
})
```
### Send Message
```typescript
const result = await sendMessage(context, {
passAddress: publicKey('PASS_ADDRESS'),
message: 'Welcome to our loyalty program!',
sender: programAuthority.publicKey,
signer: updateAuthority, // Required: Program authority of the Loyalty Program
})
console.log(result)
// {
// signature: string, // Transaction signature
// message: {
// id: string, // Unique message ID
// content: string, // Message content
// sender: string, // Sender's public key
// timestamp: number, // Message timestamp
// read: boolean // Message read status
// }
// }
```
### Mark Message as Read
```typescript
const result = await markMessageRead(context, {
passAddress: publicKey('PASS_ADDRESS'),
messageId: 'MESSAGE_ID',
signer: updateAuthority, // Required: Program authority of the Loyalty Program
})
console.log(result)
// {
// signature: string // Transaction signature
// }
```
### Get Asset Messages
```typescript
const messages = await getAssetMessages(context, publicKey('PASS_ADDRESS'))
console.log(messages)
// {
// stats: {
// total: number, // Total number of messages
// unread: number, // Number of unread messages
// read: number // Number of read messages
// },
// messages: Array<{
// id: string, // Message ID
// content: string, // Message content
// sender: string, // Sender's public key
// timestamp: number, // Message timestamp
// read: boolean // Message read status
// }>
// }
```
### Send Broadcast
```typescript
// Send broadcast to all holders
const result = await sendBroadcast(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
message: 'Welcome to our loyalty program!',
sender: programAuthority.publicKey,
signer: updateAuthority, // Required: Program authority of the Loyalty Program
})
// Send broadcast to specific holders
const specificResult = await sendBroadcast(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
message: 'VIP announcement',
sender: programAuthority.publicKey,
signer: updateAuthority,
})
console.log(result)
// {
// signature: string, // Transaction signature
// broadcast: {
// id: string, // Unique broadcast ID
// content: string, // Broadcast content
// sender: string, // Sender's public key
// timestamp: number, // Broadcast timestamp
// read: boolean, // Broadcast read status
// recipients?: { // Optional recipient information
// type: 'all' | 'tier' | 'specific',
// value?: string[] // For 'tier': tier names, For 'specific': holder addresses
// }
// }
// }
```
### Mark Broadcast as Read
```typescript
const result = await markBroadcastRead(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
broadcastId: 'BROADCAST_ID',
signer: updateAuthority, // Required: Program authority of the Loyalty Program
})
console.log(result)
// {
// signature: string // Transaction signature
// }
```
### Get Program Broadcasts
```typescript
const broadcasts = await getProgramDetails(context)
console.log(broadcasts.broadcasts)
// {
// broadcasts: Array<{
// id: string, // Broadcast ID
// content: string, // Broadcast content
// sender: string, // Sender's public key
// timestamp: number, // Broadcast timestamp
// read: boolean, // Broadcast read status
// recipients?: { // Optional recipient information
// type: 'all' | 'tier' | 'specific',
// value?: string[] // For 'tier': tier names, For 'specific': holder addresses
// }
// }>,
// totalBroadcasts: number // Total number of broadcasts
// }
```
## Voucher Management System
Verxio Protocol includes a comprehensive voucher management system for creating, distributing, and redeeming digital vouchers with full lifecycle management.
### Create Voucher Collection
You can either:
- **Provide a pre-uploaded metadata URI** (no image upload needed), or
- **Provide an image buffer and filename** to auto-upload the image and generate metadata.
#### 1. Using a pre-uploaded metadata URI
```typescript
const result = await createVoucherCollection(context, {
collectionName: 'Summer Sale Vouchers',
collectionMetadataUri: 'https://arweave.net/...', // Already uploaded metadata
updateAuthority: generateSigner(context.umi),
metadata: {
merchantName: 'Coffee Brew',
description: 'Summer sale vouchers for loyal customers',
terms: 'Valid until August 31st, 2024',
},
})
console.log(result)
// {
// collection: KeypairSigner, // Collection signer
// signature: string, // Transaction signature
// updateAuthority: KeypairSigner // Update authority for the collection
// }
```
#### 2. Uploading an image and generating metadata
```typescript
const imageBuffer = fs.readFileSync('voucher-collection.png')
const result = await createVoucherCollection(context, {
collectionName: 'Summer Sale Vouchers',
imageBuffer, // Buffer of your image
imageFilename: 'voucher-collection.png',
updateAuthority: generateSigner(context.umi),
metadata: {
merchantName: 'Coffee Brew',
description: 'Summer sale vouchers for loyal customers',
terms: 'Valid until August 31st, 2024',
},
})
// The protocol will upload the image, generate metadata, and use the resulting URI
```
### Mint Voucher
You can either:
- **Provide a pre-uploaded metadata URI** (no image upload needed), or
- **Provide an image buffer and filename** to auto-upload the image and generate metadata.
#### 1. Using a pre-uploaded metadata URI
```typescript
const result = await mintVoucher(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
voucherName: 'Summer Sale Voucher',
voucherMetadataUri: 'https://arweave.net/...', // Already uploaded metadata
voucherData: {
type: 'percentage_off',
value: 15, // 15% off
maxUses: 1,
expiryDate: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days from now
conditions: [{ type: 'minimum_purchase', value: 50, operator: 'greater_than' }],
description: '15% off your next purchase',
merchantId: 'coffee_brew_merchant_001', // String identifier for the merchant
},
recipient: publicKey('RECIPIENT_ADDRESS'),
updateAuthority: generateSigner(context.umi),
})
console.log(result)
// {
// asset: KeypairSigner, // Voucher signer
// signature: string, // Transaction signature
// voucherAddress: PublicKey // Voucher public key
// }
```
#### 2. Uploading an image and generating metadata
```typescript
const imageBuffer = fs.readFileSync('voucher.png')
const result = await mintVoucher(context, {
collectionAddress: publicKey('COLLECTION_ADDRESS'),
voucherName: 'Summer Sale Voucher',
imageBuffer, // Buffer of your image
imageFilename: 'voucher.png',
voucherData: {
type: 'percentage_off',
value: 15, // 15% off
maxUses: 1,
expiryDate: Date.now() + 30 * 24 * 60 * 60 * 1000, // 30 days from now
conditions: [{ type: 'minimum_purchase', value: 50, operator: 'greater_than' }],
description: '15% off your next purchase',
merchantId: 'coffee_brew_merchant_001', // String identifier for the merchant
},
recipient: publicKey('RECIPIENT_ADDRESS'),
updateAuthority: generateSigner(context.umi),
})
// The protocol will upload the image, generate metadata, and use the resulting URI
```
### Validate Voucher
```typescript
const validation = await validateVoucher(context, {
voucherAddress: publicKey('VOUCHER_ADDRESS'),
})
console.log(validation)
// {
// isValid: boolean,
// errors: string[],
// warnings: string[],
// voucherData: {
// type: string,
// value: number,
// currentUses: number,
// maxUses: number,
// expiryDate: number,
// conditions: string[],
// description: string,
// merchantId: string
// },
// redemptionValue: number
// }
```
### Redeem Voucher
The `redeemVoucher` function performs comprehensive validation and redemption of vouchers. It enforces merchant ID matching, validates expiry dates, usage limits, and conditions, then records the redemption in the voucher's history.
```typescript
const result = await redeemVoucher(context, {
voucherAddress: publicKey('VOUCHER_ADDRESS'),
merchantId: 'coffee_brew_merchant_001', // String identifier for the merchant
updateAuthority: generateSigner(context.umi), // Authority that can update the voucher
redemptionAmount: 100, // Purchase amount for percentage-based vouchers
redemptionDetails: {
transactionId: 'tx_123',
items: ['Coffee', 'Pastry'],
totalAmount: 100,
discountApplied: 25,
},
})
console.log(result)
// {
// instruction: TransactionBuilder, // Transaction instruction for execution
// validation: {
// errors: string[], // Validation errors if any
// voucher: VoucherData // Voucher data after validation
// },
// redemptionValue: number, // Calculated redemption value
// updatedVoucher: VoucherData // Voucher data after redemption
// }
```
### Get User Vouchers
```typescript
const vouchers = await getUserVouchers(context, {
userAddress: publicKey('USER_ADDRESS'),
filters: {
status: 'active', // 'active' | 'expired' | 'fully_used'
type: 'percentage_off', // Optional: filter by voucher type
minValue: 10, // Optional: minimum value
},
sortBy: 'expiryDate', // 'expiryDate' | 'value' | 'createdAt'
sortOrder: 'asc', // 'asc' | 'desc'
limit: 10, // Optional: limit results
})
console.log(vouchers)
// {
// vouchers: Array<{
// address: string,
// type: string,
// value: number,
// currentUses: number,
// maxUses: number,
// expiryDate: number,
// status: string,
// description: string,
// conditions: string[],
// collection: string
// }>,
// total: number,
// expiringSoon: Array<string>, // Voucher addresses expiring in 7 days
// redeemable: Array<string> // Voucher addresses that can be redeemed
// }
```
### Extend Voucher Expiry
```typescript
const result = await extendVoucherExpiry(context, {
voucherAddress: publicKey('VOUCHER_ADDRESS'),
newExpiryDate: Date.now() + 60 * 24 * 60 * 60 * 1000, // 60 days from now
reason: 'Customer request',
signer: generateSigner(context.umi),
})
console.log(result)
// {
// signature: string,
// newExpiryDate: number
// }
```
### Cancel Voucher
```typescript
const result = await cancelVoucher(context, {
voucherAddress: publicKey('VOUCHER_ADDRESS'),
reason: 'Customer refund',
signer: generateSigner(context.umi),
})
console.log(result)
// {
// signature: string,
// status: 'cancelled'
// }
```
### Merchant Identification
In the voucher system, merchants are identified using a `merchantId` string rather than a blockchain address. This provides flexibility for:
- **Off-chain Integration**: Merchants can use their existing business identifiers
- **Multi-chain Support**: Same merchant can operate across different networks
- **Privacy**: Merchant identity can be managed separately from blockchain addresses
- **Scalability**: No need to manage multiple wallet addresses per merchant
The `merchantId` is set when creating vouchers and validated during redemption to ensure vouchers are only used at the correct merchant.
### Supported Voucher Types
Verxio Protocol supports multiple voucher types for different use cases:
#### Percentage Off Vouchers
```typescript
{
type: 'percentage_off',
value: 15, // 15% discount
conditions: ['Minimum purchase: $50']
}
```
#### Fixed Credit Vouchers
```typescript
{
type: 'fixed_verxio_credits',
value: 100, // $100 in credits
conditions: ['Valid for any purchase']
}
```
#### Free Item Vouchers
```typescript
{
type: 'free_item',
value: 25, // $25 item value
conditions: ['Valid for items up to $25']
}
```
#### Buy One Get One Vouchers
```typescript
{
type: 'buy_one_get_one',
value: 30, // Free item worth $30
conditions: ['Buy any item, get one free up to $30']
}
```
#### Custom Reward Vouchers
```typescript
{
type: 'custom_reward',
value: 50, // Custom value
conditions: ['Special promotion', 'Valid with other offers']
}
```
## Instruction Functions Usage (Advanced)
Instruction-based functions provide advanced transaction composition capabilities, allowing you to batch multiple operations, optimize fees, and integrate with existing transaction flows.
### Key Benefits
- **Composability**: Combine multiple Verxio operations in a single transaction
- **Flexibility**: Add custom instructions before/after Verxio operations
- **Gas Optimization**: Batch operations to save on transaction fees
- **Integration**: Easier integration with existing transaction flows
- **Error Handling**: Validate inputs before transaction execution
### Protocol Fees
Verxio Protocol includes built-in static fees for protocol operations:
- **CREATE_LOYALTY_PROGRAM**: 0.002 SOL - Creating new loyalty programs
- **LOYALTY_OPERATIONS**: 0.001 SOL - Pass issuance and program updates
- **VERXIO_INTERACTION**: 0.0004 SOL - Points management and messaging
- **VOUCHER_OPERATIONS**: 0.0008 SOL - Voucher creation, minting, and redemption
- **VOUCHER_MANAGEMENT**: 0.0006 SOL - Voucher validation and analytics
All instruction functions include these fees by default.
### Basic Instruction Usage
```typescript
import { createLoyaltyProgramInstruction } from '@verxioprotocol/core'
// Create instruction (doesn't execute)
const { instruction, collection, updateAuthority } = createLoyaltyProgramInstruction(context, config)
// Execute when ready
const result = await instruction.sendAndConfirm(context.umi)
```
### Composing Multiple Operations
```typescript
import {
createLoyaltyProgramInstruction,
issueLoyaltyPassInstruction,
awardLoyaltyPointsInstruction,
} from '@verxioprotocol/core'
// Create individual instructions
const { instruction: createProgram, collection } = createLoyaltyProgramInstruction(context, programConfig)
const { instruction: issuePass } = issueLoyaltyPassInstruction(context, passConfig)
const { instruction: awardPoints } = await awardLoyaltyPointsInstruction(context, pointsConfig)
// Combine into single transaction
const combinedTx = createProgram.add(issuePass).add(awardPoints).add(customInstruction) // Your own instruction
// Execute with custom settings
const result = await combinedTx.sendAndConfirm(context.umi, {
confirm: { commitment: 'finalized' },
send: { skipPreflight: true },
})
```
### Available Instruction Functions
#### Core Loyalty Program Operations
- `createLoyaltyProgramInstruction` - Create a new loyalty program
- `updateLoyaltyProgramInstruction` - Update existing loyalty program
- `issueLoyaltyPassInstruction` - Issue loyalty passes to users
#### Points Management
- `awardLoyaltyPointsInstruction` - Award points for actions
- `