Referral System
Overview
The Med.Fun referral system allows users to earn passive income by inviting friends to the platform. Users receive commission on their referrals' trading volume, with rates increasing based on tier progression.
How It Works
Generate Code: User generates a unique 6-character referral code (or custom code)
Share Link: User shares referral link:
https://med.fun/ref/{CODE}Friend Signs Up: New user creates account using the referral link
Track Activity: System tracks referred user's trading volume
Earn Commission: Referrer earns percentage of trading fees
Claim Earnings: Accumulated earnings can be claimed (min $1.00)
Database Schema
referral_codes
referral_codesStores user referral codes and tracking data.
id
uuid
No
gen_random_uuid()
Primary key
code
text
No
-
Referral code (6-9 chars)
user_wallet
text
No
-
Owner's wallet address
is_custom
boolean
No
false
Whether code is custom
total_referrals
integer
No
0
Count of referrals
total_volume
numeric
No
0
Total trading volume
total_earnings
numeric
No
0
Total commissions earned
created_at
timestamptz
No
now()
Creation timestamp
updated_at
timestamptz
No
now()
Last update timestamp
Constraints:
Unique index on
code(case-insensitive)Unique index on
user_walletCheck:
length(code) >= 1 AND length(code) <= 9
RLS Policies:
Users can view their own codes
Users can create codes for themselves
Users can update their own codes
user_referrals
user_referralsTracks individual referred users and their activity.
id
uuid
No
gen_random_uuid()
Primary key
referrer_wallet
text
No
-
Referrer's wallet
referred_wallet
text
No
-
Referred user's wallet
referral_code
text
No
-
Code used
status
text
No
'active'
Status (active/inactive)
total_volume
numeric
No
0
Referred user's volume
total_earnings
numeric
No
0
Earnings from this user
created_at
timestamptz
No
now()
Referral timestamp
last_trade_at
timestamptz
Yes
null
Last trade timestamp
Constraints:
Unique constraint on
referred_walletForeign key to
referral_codes(code)
RLS Policies:
Users can view their own referrals
System can insert new referrals
referral_earnings
referral_earningsRecords individual commission payments.
id
uuid
No
gen_random_uuid()
Primary key
referrer_wallet
text
No
-
Earner's wallet
referred_wallet
text
No
-
Source user's wallet
amount
numeric
No
-
Commission amount
trade_volume
numeric
No
-
Trade that generated it
commission_rate
numeric
No
-
Rate applied
status
text
No
'pending'
pending/claimed
created_at
timestamptz
No
now()
Earned timestamp
claimed_at
timestamptz
Yes
null
Claimed timestamp
RLS Policies:
Users can view their own earnings
Users can update their own earnings (claim)
referral_tiers
referral_tiersDefines tier structure and benefits.
id
uuid
No
gen_random_uuid()
Primary key
tier_name
text
No
-
Tier name
tier_level
integer
No
-
Tier number (1-4)
min_referrals
integer
No
0
Min referrals needed
min_volume
numeric
No
0
Min volume needed
commission_rate
numeric
No
-
Commission %
benefits
jsonb
No
{}
Tier benefits
color
text
No
-
UI color
created_at
timestamptz
No
now()
Creation timestamp
Default Tiers:
Bronze
1
0
$0
10%
Base commission
Silver
2
5
$1,000
12%
Priority support, Custom codes
Gold
3
25
$10,000
15%
Custom badge, Early access
Platinum
4
100
$100,000
20%
VIP support, Account manager
referral_settings
referral_settingsUser preferences for referral notifications.
id
uuid
No
gen_random_uuid()
Primary key
user_wallet
text
No
-
User's wallet
email_notifications
boolean
No
true
Email notifications
push_notifications
boolean
No
true
Push notifications
auto_claim_threshold
numeric
Yes
null
Auto-claim amount
created_at
timestamptz
No
now()
Creation timestamp
updated_at
timestamptz
No
now()
Last update timestamp
Referral Code System
Auto-Generated Codes
Format: 6 uppercase alphanumeric characters
Example:
ABC123,XYZ789Generation: Random using
Math.random()and character setValidation: Must be unique across all users
Custom Codes
Format: 1-9 alphanumeric characters
Example:
CRYPTO,MOON,TRADERValidation:
Must be 1-9 characters
Alphanumeric only (A-Z, 0-9)
Case-insensitive uniqueness check
Cannot contain special characters
Availability: Check via database before creation
Referral Link Format
https://med.fun/ref/{CODE}Commission Structure
Base Commission
Default Rate: 10% of referred user's trading fees
Calculation:
tradingFee * commissionRateTracking: Real-time per trade
Accumulation: Added to pending earnings
Tier-Based Boosts
Commission rates increase with tier:
Bronze (Tier 1): 10% commission
Silver (Tier 2): 12% commission (+20% boost)
Gold (Tier 3): 15% commission (+50% boost)
Platinum (Tier 4): 20% commission (+100% boost)Example Calculation
Referred user makes trade: $100
Trading fee (1%): $1.00
Referrer tier: Gold (15%)
Commission: $1.00 * 0.15 = $0.15Tier Progression
Tier Requirements
Bronze (Starting Tier)
Min Referrals: 0
Min Volume: $0
Benefits: Base 10% commission
Silver Tier
Min Referrals: 5 active referrals
Min Volume: $1,000 total
Benefits: 12% commission, Priority support, Custom referral codes
Gold Tier
Min Referrals: 25 active referrals
Min Volume: $10,000 total
Benefits: 15% commission, Custom badge, Early access to features
Platinum Tier
Min Referrals: 100 active referrals
Min Volume: $100,000 total
Benefits: 20% commission, VIP support, Dedicated account manager
Tier Calculation Logic
// Find highest tier user qualifies for
const currentTier = tiers
.filter(tier =>
totalReferrals >= tier.min_referrals &&
totalVolume >= tier.min_volume
)
.sort((a, b) => b.tier_level - a.tier_level)[0];Progress Tracking
// Calculate progress to next tier
const nextTier = tiers.find(t => t.tier_level === currentTier.tier_level + 1);
if (nextTier) {
const referralProgress = (totalReferrals / nextTier.min_referrals) * 100;
const volumeProgress = (totalVolume / nextTier.min_volume) * 100;
const overallProgress = Math.min(referralProgress, volumeProgress);
}Claiming Earnings
Claim Requirements
Minimum Amount: $1.00 USD
Status: Must be 'pending'
User Action: Manual claim via dashboard
Claim Process
async function claimEarnings() {
// 1. Check minimum threshold
if (pendingEarnings < 1.00) {
return error("Minimum $1.00 required");
}
// 2. Update earnings status
await supabase
.from('referral_earnings')
.update({
status: 'claimed',
claimed_at: new Date()
})
.eq('referrer_wallet', userWallet)
.eq('status', 'pending');
// 3. Refresh data
await fetchReferralData();
}Transaction Flow
User clicks "Claim Earnings" button
Frontend validates minimum amount
Backend updates earnings records
Status changes:
pending→claimedclaimed_attimestamp recordedUI updates with new balances
Real-time Updates
Supabase Subscriptions
Referral Updates:
const referralsChannel = supabase
.channel('user_referrals_changes')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'user_referrals',
filter: `referrer_wallet=eq.${userWallet}`
},
() => fetchReferralData()
)
.subscribe();Earnings Updates:
const earningsChannel = supabase
.channel('referral_earnings_changes')
.on(
'postgres_changes',
{
event: '*',
schema: 'public',
table: 'referral_earnings',
filter: `referrer_wallet=eq.${userWallet}`
},
() => fetchReferralData()
)
.subscribe();Frontend Components
useReferrals Hook
useReferrals HookLocation: /src/hooks/useReferrals.tsx
Purpose: Manages all referral data and operations
State Management:
const {
referralCode, // User's code
referralLink, // Full referral URL
totalReferrals, // Count of referrals
activeReferrals, // Active referrals count
totalVolume, // Cumulative volume
totalEarnings, // Total earned
pendingEarnings, // Unclaimed amount
claimedEarnings, // Claimed amount
userReferrals, // Array of referrals
referralEarnings, // Earnings history
currentTier, // Current tier object
nextTier, // Next tier object
tierProgress, // Progress percentage
loading, // Loading state
claiming, // Claiming state
generateReferralCode, // Function
claimEarnings, // Function
copyReferralLink, // Function
refreshData // Function
} = useReferrals(userWallet);Key Functions:
generateReferralCode:
async function generateReferralCode(customCode?: string) {
if (customCode) {
// Validate custom code
if (!/^[A-Z0-9]{1,9}$/.test(customCode.toUpperCase())) {
throw new Error("Invalid format");
}
// Check availability
const exists = await checkCodeExists(customCode);
if (exists) {
throw new Error("Code already taken");
}
}
const code = customCode || generateRandomCode();
await supabase
.from('referral_codes')
.insert({
code: code.toUpperCase(),
user_wallet: userWallet,
is_custom: !!customCode
});
}claimEarnings:
async function claimEarnings() {
if (pendingEarnings < 1) {
throw new Error("Minimum $1.00 required");
}
await supabase
.from('referral_earnings')
.update({
status: 'claimed',
claimed_at: new Date().toISOString()
})
.eq('referrer_wallet', userWallet)
.eq('status', 'pending');
toast.success("Earnings claimed successfully!");
}copyReferralLink:
function copyReferralLink() {
const link = `${window.location.origin}/ref/${referralCode}`;
navigator.clipboard.writeText(link);
toast.success("Referral link copied!");
}ReferralDashboard Component
ReferralDashboard ComponentLocation: /src/components/ReferralDashboard.tsx
Features:
Tabbed interface (Overview, Referrals, Settings)
Referral code display and generation
Link sharing (copy + native share API)
Earnings summary with claim button
Referral list with status and earnings
Tier progress visualization
Mobile-responsive (Sheet on mobile, Dialog on desktop)
UI Structure:
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="referrals">Referrals</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="overview">
{/* Code, earnings, stats, tier progress */}
</TabsContent>
<TabsContent value="referrals">
{/* Referral list with details */}
</TabsContent>
<TabsContent value="settings">
{/* Tier benefits and settings */}
</TabsContent>
</Tabs>ReferralStatsCard Component
ReferralStatsCard ComponentLocation: /src/components/ReferralStatsCard.tsx
Purpose: Summary card showing key metrics
Displayed Data:
Active referrals count
Total earnings
Pending earnings
"View Details" button
Integration Points
User Signup Flow
// When new user signs up with referral code
async function handleSignupWithReferral(wallet: string, code: string) {
// 1. Verify referral code exists
const { data: referralCode } = await supabase
.from('referral_codes')
.select('*')
.eq('code', code.toUpperCase())
.single();
if (!referralCode) return;
// 2. Create referral relationship
await supabase
.from('user_referrals')
.insert({
referrer_wallet: referralCode.user_wallet,
referred_wallet: wallet,
referral_code: code.toUpperCase(),
status: 'active'
});
// 3. Update referral code stats
await supabase
.from('referral_codes')
.update({
total_referrals: referralCode.total_referrals + 1
})
.eq('id', referralCode.id);
}Trade Commission Tracking
// When referred user makes a trade
async function recordTradeCommission(
referredWallet: string,
tradeVolume: number,
tradeFee: number
) {
// 1. Get referral relationship
const { data: referral } = await supabase
.from('user_referrals')
.select('*, referral_codes!inner(*)')
.eq('referred_wallet', referredWallet)
.eq('status', 'active')
.single();
if (!referral) return;
// 2. Get referrer's tier
const tier = await getCurrentTier(referral.referrer_wallet);
// 3. Calculate commission
const commission = tradeFee * (tier.commission_rate / 100);
// 4. Record earning
await supabase
.from('referral_earnings')
.insert({
referrer_wallet: referral.referrer_wallet,
referred_wallet: referredWallet,
amount: commission,
trade_volume: tradeVolume,
commission_rate: tier.commission_rate,
status: 'pending'
});
// 5. Update stats
await updateReferralStats(referral.referrer_wallet, tradeVolume, commission);
}User Flows
Flow 1: Generate and Share Code
1. User connects wallet
2. User clicks "Generate Referral Code"
3. System generates 6-char code (or accepts custom)
4. Code saved to database
5. Referral link displayed
6. User clicks "Copy Link"
7. Link copied to clipboard
8. User shares link externallyFlow 2: Earn Commission
1. Friend clicks referral link
2. Friend creates account
3. Referral relationship created in database
4. Friend makes first trade
5. Trade fee calculated (1%)
6. Commission calculated based on tier (10-20%)
7. Earning recorded as 'pending'
8. Referrer sees new earning in dashboard
9. Real-time update via Supabase subscriptionFlow 3: Claim Earnings
1. User opens referral dashboard
2. Pending earnings displayed
3. User clicks "Claim Earnings"
4. System checks minimum ($1.00)
5. Status updated to 'claimed'
6. claimed_at timestamp recorded
7. UI updates balances
8. Success toast displayedFlow 4: Tier Progression
1. User accumulates referrals and volume
2. System checks tier requirements
3. Requirements met for next tier
4. Tier automatically upgraded
5. Commission rate increased
6. New benefits unlocked
7. Progress bar updates
8. Notification displayedAPI Reference
Database Functions
(None currently - all logic in application layer)
RLS Helper Functions
-- Check if user owns referral code
CREATE FUNCTION user_owns_referral_code(code_id uuid)
RETURNS boolean AS $$
SELECT EXISTS (
SELECT 1 FROM referral_codes
WHERE id = code_id
AND user_wallet = (current_setting('request.jwt.claims')::json->>'sub')
);
$$ LANGUAGE sql SECURITY DEFINER;Best Practices
For Developers
1. Always validate referral codes:
if (!/^[A-Z0-9]{1,9}$/.test(code)) {
throw new Error("Invalid code format");
}2. Use transactions for multi-step operations:
// When creating referral relationship
await supabase.rpc('create_referral', {
p_referrer: referrerWallet,
p_referred: referredWallet,
p_code: code
});3. Handle race conditions:
// Use database constraints and ON CONFLICT
INSERT INTO user_referrals (...)
ON CONFLICT (referred_wallet) DO NOTHING;4. Monitor real-time subscriptions:
// Clean up subscriptions on unmount
useEffect(() => {
return () => {
supabase.removeChannel(channel);
};
}, []);For Product
1. Minimum payout prevents micro-transactions
$1.00 minimum balances gas costs and prevents spam
2. Tier system encourages growth
Progressive rewards incentivize user acquisition
3. Real-time updates build trust
Instant feedback on earnings creates positive UX
4. Custom codes enable branding
Personal codes improve conversion rates
Troubleshooting
Code Already Exists
Error: "Referral code already taken" Solution: Try a different custom code or use auto-generated code
Earnings Not Appearing
Check:
Is referred user's account active?
Has referred user completed trades?
Check database for pending earnings
Verify real-time subscription is active
Cannot Claim Earnings
Check:
Is pending balance >= $1.00?
Are earnings in 'pending' status?
Check wallet connection
Verify RLS policies allow update
Tier Not Updating
Check:
Verify referral count meets minimum
Verify volume meets minimum
Check tier calculation logic
Refresh dashboard data
Performance Considerations
Database Indexes
CREATE INDEX idx_referral_codes_wallet ON referral_codes(user_wallet);
CREATE INDEX idx_user_referrals_referrer ON user_referrals(referrer_wallet);
CREATE INDEX idx_referral_earnings_referrer ON referral_earnings(referrer_wallet);
CREATE INDEX idx_referral_earnings_status ON referral_earnings(status);Query Optimization
Use
select('*')sparingly, fetch only needed columnsImplement pagination for large referral lists
Cache tier data to reduce database calls
Use database views for complex aggregations
Future Enhancements
Potential Features
Auto-Claim: Automatic claiming at threshold
Leaderboards: Top referrers displayed publicly
Bonus Rewards: Limited-time commission boosts
Team Referrals: Multi-level commission structure
Analytics: Detailed referral performance metrics
Email Notifications: Alerts for new referrals and earnings
Technical Improvements
Edge function for commission calculation
Webhooks for real-time trade notifications
GraphQL API for complex queries
Caching layer for frequently accessed data
Last updated
Was this helpful?