This commit is contained in:
zramsay
2025-03-21 17:17:30 -04:00
parent 127a20ba86
commit 5a589469f5
3 changed files with 88 additions and 55 deletions
+56
View File
@@ -114,3 +114,59 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
- Details about each uploaded image
- The system prevents duplicate image uploads and point awards
- Only authenticated users can earn and view points
## WILD Token Integration with Sei Blockchain
This application rewards users with WILD tokens on the Sei blockchain when they identify wildlife images. The token distribution is handled by a secure backend service.
### User Flow
1. Users upload wildlife images and earn points in Supabase
2. Users who connect a wallet (Keplr or Leap) also receive WILD tokens automatically
3. Tokens are awarded based on the species identified (rare species earn more tokens)
### Backend Service Setup
The token distribution backend is located in the `sei-backend-src` directory.
#### Setup Steps
1. Navigate to the backend directory:
```bash
cd sei-backend-src
```
2. Install dependencies:
```bash
npm install
```
3. Build the service:
```bash
npm run build
```
4. Configure the service by creating a `.env` file (copy from `.env.example`):
```bash
cp .env.example .env
```
5. Edit the `.env` file with your actual configuration:
- `SEI_TOKEN_CONTRACT_ADDRESS`: Your WILD token contract address
- `DISTRIBUTOR_MNEMONIC`: The mnemonic phrase for your distributor wallet
- `API_KEY`: A secure API key for authentication
6. Start the service:
```bash
./start.sh
```
### Frontend Configuration
Configure the following environment variables in your frontend's `.env.local`:
```
# Token Backend Service
NEXT_PUBLIC_TOKEN_BACKEND_URL=http://localhost:3001
NEXT_PUBLIC_TOKEN_API_KEY=your-api-key-here
```
+1 -49
View File
@@ -175,55 +175,7 @@ export const getWalletAddress = (): string | null => {
return currentAddress;
};
/**
* Award WILD tokens to a user for wildlife sighting
* This interacts with the Wildlife Token smart contract on Sei
*/
export const awardTokensForWildlife = async (
species: string,
amount: number = 10
): Promise<{ success: boolean; txHash?: string; error?: string }> => {
try {
if (!isWalletConnected() || !currentAddress || !cosmWasmClient) {
return {
success: false,
error: 'Wallet not connected'
};
}
// WILD token contract address from environment or config
const tokenAddress = NETWORKS.testnet.tokenFactoryAddress;
if (!tokenAddress) {
return {
success: false,
error: 'WILD token contract address not configured'
};
}
// Execute CosmWasm contract message to award WILD tokens based on species
// The contract determines the actual amount based on species rarity
const result = await cosmWasmClient.execute(
currentAddress,
tokenAddress,
{ award_tokens: { recipient: currentAddress, species: species.toLowerCase() } },
'auto',
undefined, // memo
[] // funds - no funds sent with this execution
);
console.log('WILD tokens awarded successfully:', result);
return {
success: true,
txHash: result.transactionHash
};
} catch (error) {
console.error('Error awarding WILD tokens:', error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error during token award'
};
}
};
// Award tokens function removed - now handled by the backend service
/**
* Get WILD token balance for connected wallet
+31 -6
View File
@@ -1,5 +1,4 @@
// src/services/blockchain/tokenRewardService.ts
import { awardTokensForWildlife } from './seiService';
import { isWalletConnected, getWalletAddress } from './seiService';
// Note: These reward amounts are for display purposes only
@@ -75,14 +74,40 @@ export const awardTokensForSighting = async (species: string, points?: number):
totalReward = baseReward + rareBonus;
}
// Award WILD tokens through Sei contract based on species and amount
const result = await awardTokensForWildlife(species, totalReward);
// 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 || '';
const walletAddress = getWalletAddress();
if (!walletAddress) {
throw new Error('No wallet address available');
}
// 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 ${totalReward} tokens for ${species} sighting to wallet ${getWalletAddress()}`);
console.log(`Awarded tokens for ${species} sighting to wallet ${walletAddress}`);
return {
success: true,
tokenAmount: totalReward,
tokenAmount: result.amount,
txHash: result.txHash,
walletConnected: true
};