ranger-app/src/services/blockchain/tokenRewardService.ts
2025-03-21 20:35:52 -04:00

166 lines
5.4 KiB
TypeScript

// src/services/blockchain/tokenRewardService.ts
import { isWalletConnected, getWalletAddress } from './seiService';
// Note: These reward amounts are for display purposes only
// The actual reward amounts are determined by the WILD token contract on Sei
export const TOKEN_REWARDS = {
WILDLIFE_SIGHTING: 10, // Base WILD token reward for any wildlife sighting
RARE_SPECIES: 25, // Additional WILD tokens for rare species
};
// List of species considered rare for bonus rewards
const RARE_SPECIES = [
'elephant',
'tiger',
'rhino',
'panda',
'gorilla',
'whale',
'dolphin',
'snow leopard',
'eagle',
// Add more rare species as needed
];
/**
* Determine if a species is considered rare
* @param species The detected animal species
* @returns True if the species is considered rare
*/
export const isRareSpecies = (species: string): boolean => {
if (!species) return false;
const normalizedSpecies = species.toLowerCase().trim();
return RARE_SPECIES.some(rareSpecies =>
normalizedSpecies.includes(rareSpecies)
);
};
/**
* Award tokens for a wildlife sighting if wallet is connected
* @param species The detected animal species
* @param points Optional number of points to convert to tokens (if not provided, calculates based on species)
* @param explicitWalletAddress Optional wallet address to use instead of checking connection state
* @returns Object containing success status and transaction info
*/
export const awardTokensForSighting = async (
species: string,
points?: number,
explicitWalletAddress?: string
): Promise<{
success: boolean;
tokenAmount?: number;
txHash?: string;
error?: string;
walletConnected: boolean;
}> => {
try {
// Determine wallet address - either from parameter or connected wallet
let walletAddress = explicitWalletAddress;
// If explicit address was provided, use it directly (server-side case)
if (walletAddress) {
console.log('Using explicitly provided wallet address:', walletAddress);
} else {
// Client-side case - check if wallet is connected
console.log('No explicit wallet address provided, checking wallet connection state...');
// Try to get from memory first
if (isWalletConnected()) {
walletAddress = getWalletAddress();
console.log('Found connected wallet in memory:', walletAddress);
}
// Try localStorage as a fallback (client-side only)
if (!walletAddress && typeof window !== 'undefined') {
try {
const storedAddress = localStorage.getItem('wildlife_wallet_address');
if (storedAddress) {
console.log('Using wallet address from localStorage:', storedAddress);
walletAddress = storedAddress;
}
} catch (e) {
console.warn('Error accessing localStorage:', e);
}
}
// If we still don't have an address, return no wallet connected
if (!walletAddress) {
console.log('No wallet connected, skipping token award.');
return {
success: false,
error: 'No wallet connected',
walletConnected: false
};
}
}
// Validate we have a wallet address by this point
if (!walletAddress) {
console.log('No valid wallet address available for token award.');
return {
success: false,
error: 'No wallet address available',
walletConnected: false
};
}
console.log('Processing token award for wallet:', walletAddress);
// Calculate token reward amount - either from points or from species
let totalReward: number;
if (typeof points === 'number' && points > 0) {
// If points are provided, use them directly (1 point = 1 token)
totalReward = points;
} else {
// Otherwise calculate based on species
const baseReward = TOKEN_REWARDS.WILDLIFE_SIGHTING;
const isRare = isRareSpecies(species);
const rareBonus = isRare ? TOKEN_REWARDS.RARE_SPECIES : 0;
totalReward = baseReward + rareBonus;
}
// Call the backend service to award tokens through the distributor
const apiUrl = process.env.NEXT_PUBLIC_TOKEN_BACKEND_URL || 'http://localhost:3001';
const apiKey = process.env.NEXT_PUBLIC_TOKEN_API_KEY || '';
// Request tokens from the backend service
const response = await fetch(`${apiUrl}/api/award-tokens`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey
},
body: JSON.stringify({
recipientAddress: walletAddress,
species: species.toLowerCase()
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Error from token service');
}
const result = await response.json();
if (result.success) {
console.log(`Awarded tokens for ${species} sighting to wallet ${walletAddress}`);
return {
success: true,
tokenAmount: result.amount,
txHash: result.txHash,
walletConnected: true
};
} else {
throw new Error(result.error || 'Failed to award tokens');
}
} catch (error) {
console.error('Error in token reward service:', error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error processing token reward',
walletConnected: true
};
}
};