mirror of
https://github.com/mito-systems/ranger-app.git
synced 2026-09-07 22:04:05 +00:00
try
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user