Learn how to effectively manage points and currencies in your DRIP realm. This guide covers everything from basic point operations to advanced currency management strategies.
Overview
DRIP’s point system is highly flexible, allowing you to create multiple currencies, manage complex reward structures, and build engaging gamification experiences for your community.
Points in DRIP are called “Realm Points” and can be customized with names, emojis, and branding to match your community’s theme.
Understanding Realm Points
Point Types
Primary Currency Your main point system (e.g., XP, Coins, Tokens)
Usually the most visible to members
Used for major rewards and purchases
Often tied to overall member ranking
Secondary Currencies Additional point types for specific purposes
Event-specific points (e.g., “Summer Points”)
Category-specific rewards (e.g., “Art Coins”)
Premium currencies (e.g., “Gems”)
Point Properties
Each Realm Point has these key properties:
const realmPoint = {
id: "507f1f77bcf86cd799439015" ,
name: "Community XP" ,
emoji: "⭐" ,
description: "Experience points for community participation" ,
isDefault: true ,
isTransferable: true ,
minimumBalance: 0 ,
maximumBalance: 1000000
};
Basic Point Operations
Awarding Points
async function awardPoints ( client , memberId , points , reason = '' ) {
try {
const result = await client . request ( 'PATCH' ,
`/realm/ ${ client . realmId } /members/ ${ memberId } /point-balance` ,
{ tokens: points }
);
console . log ( `✅ Awarded ${ points } points to member ${ memberId } ` );
if ( reason ) console . log ( `Reason: ${ reason } ` );
return result ;
} catch ( error ) {
console . error ( `❌ Failed to award points: ${ error . message } ` );
throw error ;
}
}
// Examples
await awardPoints ( client , 'member123' , 100 , 'Completed daily quest' );
await awardPoints ( client , 'member456' , 50 , 'Helpful community contribution' );
Deducting Points
// Deduct points (negative amount)
await awardPoints ( client , 'member123' , - 25 , 'Minor rule violation penalty' );
// Or use a dedicated deduction function
async function deductPoints ( client , memberId , points , reason = '' ) {
return await awardPoints ( client , memberId , - Math . abs ( points ), reason );
}
Checking Balances
async function getPointBalance ( client , memberId ) {
const members = await client . searchMembers ( 'drip-id' , memberId );
if ( members . data && members . data . length > 0 ) {
const member = members . data [ 0 ];
return member . pointBalances || [];
}
throw new Error ( 'Member not found' );
}
// Usage
const balances = await getPointBalance ( client , 'member123' );
balances . forEach ( balance => {
console . log ( ` ${ balance . realmPoint . name } : ${ balance . balance } ${ balance . realmPoint . emoji } ` );
});
Advanced Point Management
Multiple Currency Systems
Manage different types of points for different purposes:
class MultiCurrencyManager {
constructor ( client ) {
this . client = client ;
this . currencies = new Map ();
}
async loadCurrencies () {
// Load available realm points
const realmPoints = await this . client . getRealmPoints ();
for ( const point of realmPoints . data ) {
this . currencies . set ( point . name . toLowerCase (), {
id: point . id ,
name: point . name ,
emoji: point . emoji ,
isDefault: point . isDefault
});
}
}
async awardCurrency ( memberId , currencyName , amount , reason = '' ) {
const currency = this . currencies . get ( currencyName . toLowerCase ());
if (! currency ) {
throw new Error ( `Currency ' ${ currencyName } ' not found` );
}
return await this . client . request ( 'PATCH' ,
`/realm/ ${ this . client . realmId } /members/ ${ memberId } /point-balance` ,
{
tokens: amount ,
realmPointId: currency . id
}
);
}
async transferBetweenCurrencies ( memberId , fromCurrency , toCurrency , amount ) {
// Convert points between different currencies
// This would need custom business logic for exchange rates
const exchangeRate = this . getExchangeRate ( fromCurrency , toCurrency );
const convertedAmount = Math . floor ( amount * exchangeRate );
// Deduct from source currency
await this . awardCurrency ( memberId , fromCurrency , - amount , 'Currency conversion' );
// Add to target currency
await this . awardCurrency ( memberId , toCurrency , convertedAmount , 'Currency conversion' );
return { originalAmount: amount , convertedAmount , exchangeRate };
}
getExchangeRate ( fromCurrency , toCurrency ) {
// Define your exchange rates
const rates = {
'xp_to_coins' : 0.1 , // 10 XP = 1 Coin
'coins_to_gems' : 0.01 , // 100 Coins = 1 Gem
'gems_to_coins' : 100 , // 1 Gem = 100 Coins
};
const rateKey = ` ${ fromCurrency } _to_ ${ toCurrency } ` ;
return rates [ rateKey ] || 1 ;
}
}
Batch Point Operations
Efficiently update multiple members at once:
async function batchPointAward ( client , awards ) {
// awards = [{ memberId, points, reason }, ...]
const updates = awards . map ( award => ({
memberId: award . memberId ,
tokens: award . points
}));
try {
const result = await client . request ( 'PATCH' ,
`/realm/ ${ client . realmId } /members/transaction` ,
{ updates }
);
console . log ( `✅ Batch awarded points to ${ awards . length } members` );
return result ;
} catch ( error ) {
console . error ( '❌ Batch point award failed:' , error . message );
throw error ;
}
}
// Usage examples
await batchPointAward ( client , [
{ memberId: 'member1' , points: 100 , reason: 'Event participation' },
{ memberId: 'member2' , points: 150 , reason: 'Contest winner' },
{ memberId: 'member3' , points: 75 , reason: 'Helpful member' }
]);
Point Transfer Between Members
Enable peer-to-peer point transfers:
async function transferPoints ( client , senderId , recipientId , amount , currency = null ) {
try {
const transferData = {
tokens: amount ,
recipientId: recipientId
};
if ( currency ) {
transferData . realmPointId = currency ;
}
const result = await client . request ( 'PATCH' ,
`/realm/ ${ client . realmId } /members/ ${ senderId } /transfer` ,
transferData
);
console . log ( `✅ Transferred ${ amount } points from ${ senderId } to ${ recipientId } ` );
return result ;
} catch ( error ) {
console . error ( `❌ Transfer failed: ${ error . message } ` );
throw error ;
}
}
// Usage
await transferPoints ( client , 'sender123' , 'recipient456' , 50 );
Gamification Strategies
Point Earning Systems
Reward different types of community engagement: const activityRewards = {
'message_sent' : 5 ,
'reaction_added' : 2 ,
'voice_joined' : 10 ,
'helpful_reaction' : 15 ,
'first_message_daily' : 25 ,
'streak_7_days' : 100
};
async function rewardActivity ( client , memberId , activity ) {
const points = activityRewards [ activity ];
if ( points ) {
await awardPoints ( client , memberId , points , `Activity: ${ activity } ` );
}
}
Reward members for reaching specific milestones: const milestones = [
{ threshold: 100 , reward: 50 , title: 'Newcomer' },
{ threshold: 500 , reward: 100 , title: 'Regular' },
{ threshold: 1000 , reward: 200 , title: 'Veteran' },
{ threshold: 5000 , reward: 500 , title: 'Legend' }
];
async function checkMilestones ( client , memberId , currentPoints ) {
for ( const milestone of milestones ) {
if ( currentPoints >= milestone . threshold ) {
// Check if already awarded (you'd track this in your database)
const alreadyAwarded = await hasAwardedMilestone ( memberId , milestone . threshold );
if (! alreadyAwarded ) {
await awardPoints ( client , memberId , milestone . reward ,
`Milestone achieved: ${ milestone . title } ` );
await recordMilestoneAwarded ( memberId , milestone . threshold );
}
}
}
}
Implement daily, weekly, or seasonal bonuses: class TimeBonusManager {
async getDailyBonus ( client , memberId ) {
const today = new Date (). toDateString ();
const lastClaim = await getLastBonusClaim ( memberId );
if ( lastClaim !== today ) {
const bonusAmount = 25 ;
await awardPoints ( client , memberId , bonusAmount , 'Daily bonus' );
await recordBonusClaim ( memberId , today );
return bonusAmount ;
}
return 0 ;
}
async getWeeklyBonus ( client , memberId ) {
const streak = await getLoginStreak ( memberId );
if ( streak >= 7 ) {
const bonusAmount = 100 + ( streak * 5 ); // Escalating bonus
await awardPoints ( client , memberId , bonusAmount , 'Weekly streak bonus' );
return bonusAmount ;
}
return 0 ;
}
}
Leaderboards and Rankings
Create competitive elements with point-based rankings:
class LeaderboardManager {
constructor ( client ) {
this . client = client ;
}
async getTopMembers ( limit = 10 , currencyId = null ) {
const members = await this . client . searchMembers ( 'drip-id' , 'all' );
return members . data
. filter ( member => member . pointBalances && member . pointBalances . length > 0 )
. map ( member => {
const balance = currencyId
? member . pointBalances . find ( b => b . realmPoint . id === currencyId )
: member . pointBalances [ 0 ];
return {
id: member . id ,
name: member . displayName || member . username ,
points: balance ?. balance || 0 ,
currency: balance ?. realmPoint . name || 'Unknown'
};
})
. sort (( a , b ) => b . points - a . points )
. slice ( 0 , limit )
. map (( member , index ) => ({ ... member , rank: index + 1 }));
}
async getMemberRank ( memberId , currencyId = null ) {
const leaderboard = await this . getTopMembers ( 1000 , currencyId );
const memberRank = leaderboard . find ( entry => entry . id === memberId );
return memberRank ? memberRank . rank : null ;
}
async getSeasonalLeaderboard ( season , currencyId = null ) {
// This would require tracking seasonal points separately
// Implementation depends on your seasonal point tracking system
const seasonalPoints = await this . getSeasonalPoints ( season , currencyId );
return seasonalPoints
. sort (( a , b ) => b . points - a . points )
. map (( entry , index ) => ({ ... entry , rank: index + 1 }));
}
}
Point Economy Design
Balancing Your Economy
Inflation Control Prevent point inflation by:
Setting reasonable earning rates
Creating point sinks (ways to spend points)
Implementing diminishing returns
Regular economy reviews
Engagement Optimization Optimize for engagement by:
Rewarding diverse activities
Providing clear progression paths
Balancing effort vs. reward
Regular feedback and adjustments
Point Sink Strategies
Create ways for members to spend their points:
const pointSinks = {
store_items: {
'premium_role' : { cost: 1000 , duration: '30 days' },
'custom_emoji' : { cost: 500 , permanent: true },
'channel_access' : { cost: 250 , duration: '7 days' }
},
services: {
'priority_support' : { cost: 100 , duration: '24 hours' },
'custom_title' : { cost: 300 , permanent: true },
'event_priority' : { cost: 150 , duration: 'next event' }
},
gambling: {
'daily_lottery' : { cost: 10 , chance_to_win: 0.1 , payout: 200 },
'point_doubler' : { cost: 50 , chance_to_win: 0.3 , payout: 100 }
}
};
Analytics and Monitoring
Point Flow Tracking
Monitor how points move through your economy:
class PointAnalytics {
constructor ( client ) {
this . client = client ;
this . transactions = [];
}
recordTransaction ( type , memberId , amount , reason ) {
this . transactions . push ({
timestamp: Date . now (),
type , // 'award', 'deduct', 'transfer'
memberId ,
amount ,
reason
});
}
getEconomyStats ( timeframe = '7d' ) {
const cutoff = Date . now () - this . getTimeframeMs ( timeframe );
const recentTransactions = this . transactions . filter ( t => t . timestamp > cutoff );
return {
totalAwarded: recentTransactions
. filter ( t => t . type === 'award' )
. reduce (( sum , t ) => sum + t . amount , 0 ),
totalDeducted: recentTransactions
. filter ( t => t . type === 'deduct' )
. reduce (( sum , t ) => sum + Math . abs ( t . amount ), 0 ),
totalTransfers: recentTransactions
. filter ( t => t . type === 'transfer' )
. reduce (( sum , t ) => sum + t . amount , 0 ),
netPointsCreated: recentTransactions
. reduce (( sum , t ) => {
if ( t . type === 'award' ) return sum + t . amount ;
if ( t . type === 'deduct' ) return sum - Math . abs ( t . amount );
return sum ; // transfers don't create/destroy points
}, 0 )
};
}
getTimeframeMs ( timeframe ) {
const units = {
'd' : 24 * 60 * 60 * 1000 ,
'h' : 60 * 60 * 1000 ,
'm' : 60 * 1000
};
const value = parseInt ( timeframe );
const unit = timeframe . slice (- 1 );
return value * ( units [ unit ] || units . d );
}
}
Best Practices
Keep point values meaningful and consistent: // ✅ Good: Consistent scaling
const rewards = {
simple_task: 10 ,
medium_task: 25 ,
complex_task: 50 ,
major_contribution: 100
};
// ❌ Bad: Inconsistent scaling
const badRewards = {
simple_task: 5 ,
medium_task: 100 ,
complex_task: 15 ,
major_contribution: 1000
};
Always handle point operations gracefully: async function safePointAward ( client , memberId , points , reason ) {
try {
// Validate inputs
if (! memberId || typeof points !== 'number' || points === 0 ) {
throw new Error ( 'Invalid award parameters' );
}
// Check if member exists
const members = await client . searchMembers ( 'drip-id' , memberId );
if (! members . data || members . data . length === 0 ) {
throw new Error ( 'Member not found' );
}
// Award points
const result = await awardPoints ( client , memberId , points , reason );
// Log successful transaction
console . log ( `✅ ${ points } points awarded to ${ memberId } : ${ reason } ` );
return result ;
} catch ( error ) {
// Log error
console . error ( `❌ Failed to award points: ${ error . message } ` );
// Don't throw for non-critical errors
return null ;
}
}
Next Steps
Building a point economy? Join our Discord community to discuss strategies and get feedback from other developers! 💰