This guide will help you set up the backend API routes that handle admin-signed transactions for DeFiWise.
The DeFiWise smart contracts require admin authorization for:
reward_quiz- Awarding XP tokens to usersmint_badge- Minting NFT badges for module completion
These functions check for admin.require_auth() in the contract code, meaning only the admin can sign these transactions. Since a regular user's wallet cannot provide the admin's signature, we need a backend service to sign these transactions.
User Wallet → Frontend → Backend API → Smart Contract
↓
Admin Private Key
(Signs Transaction)
-
The admin public key is already defined in
src/lib/stellar.ts:export const ADMIN_PUBLIC_KEY = "GASHSELFFKPP5BTMD73FBODXO65MLGP4JCRIXQNEM3RYCWMRKSGOUVHC";
-
You need the secret key (private key) for this account. If you don't have it:
- If this is a test account, you can generate a new keypair:
import * as StellarSdk from "@stellar/stellar-sdk"; const pair = StellarSdk.Keypair.random(); console.log("Public:", pair.publicKey()); console.log("Secret:", pair.secret());
- Update the
ADMIN_PUBLIC_KEYinsrc/lib/stellar.tswith your new public key - Use the secret key in the next step
- If this is a test account, you can generate a new keypair:
-
Important: The secret key starts with
S(e.g.,SXXXXX...)
-
Copy the example environment file:
copy .env.example .env
-
Edit
.envand add your admin secret key:NODE_ENV=development # CRITICAL: Keep this secret! Never commit to git! ADMIN_SECRET_KEY=SXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Optional: Rate limiting (defaults shown) RATE_LIMIT_WINDOW_MS=60000 RATE_LIMIT_MAX_REQUESTS=10
-
Verify
.envis in.gitignore(it already is by default)
The admin account needs XLM for transaction fees:
-
Visit the Stellar testnet friendbot:
https://friendbot.stellar.org?addr=YOUR_ADMIN_PUBLIC_KEY -
Replace
YOUR_ADMIN_PUBLIC_KEYwith your admin public key -
You should receive 10,000 test XLM
-
Start the development server:
npm run dev
-
Test the endpoints using curl or Postman:
Test reward-quiz:
curl -X POST http://localhost:3000/api/reward-quiz ^ -H "Content-Type: application/json" ^ -d "{\"userPublicKey\":\"GXXXXXX...\",\"challengeId\":\"test-01\",\"correct\":8,\"total\":10,\"maxXp\":100}"
Test mint-badge:
curl -X POST http://localhost:3000/api/mint-badge ^ -H "Content-Type: application/json" ^ -d "{\"userPublicKey\":\"GXXXXXX...\",\"moduleId\":\"test-module\",\"moduleTitle\":\"Test\",\"xpEarned\":100,\"quizScore\":80}"
-
Replace
GXXXXXX...with a valid testnet user public key
Use the provided client utilities in your components:
import { rewardQuiz, mintBadge } from "@/lib/api-client";
// Award XP for quiz completion
const result = await rewardQuiz({
userPublicKey: user.publicKey,
challengeId: "quiz-01",
correct: 8,
total: 10,
maxXp: 100,
});
// Mint badge for module completion
const badge = await mintBadge({
userPublicKey: user.publicKey,
moduleId: "module-01",
moduleTitle: "DeFi Basics",
xpEarned: 250,
quizScore: 85,
});See src/components/examples/QuizCompletionExample.tsx for a complete example.
git add .
git commit -m "Add backend API routes"
git push- Go to vercel.com and sign in
- Click "New Project"
- Import your GitHub repository
- Add environment variables:
- Click "Environment Variables"
- Add
ADMIN_SECRET_KEYwith your secret key - Add
RATE_LIMIT_WINDOW_MS(optional, default: 60000) - Add
RATE_LIMIT_MAX_REQUESTS(optional, default: 10)
- Click "Deploy"
Test the production endpoints:
curl -X POST https://your-app.vercel.app/api/reward-quiz ^
-H "Content-Type: application/json" ^
-d "{\"userPublicKey\":\"GXXXXXX...\",\"challengeId\":\"test-01\",\"correct\":8,\"total\":10,\"maxXp\":100}"-
.envfile is in.gitignoreand never committed -
ADMIN_SECRET_KEYis only in environment variables - Secret key is not in any client-side code
- Secret key is not logged or displayed
- Production environment variables are set in Vercel dashboard
- Rate limiting is enabled
- Input validation is working (test with invalid data)
- Make sure
.envfile exists and containsADMIN_SECRET_KEY=S... - Restart the dev server after creating
.env - In production, check Vercel environment variables
- Ensure the user public key starts with
G - Verify it's a valid Stellar public key (56 characters)
- Verify the admin account has enough XLM for fees
- Check that the contract addresses in
src/lib/stellar.tsare correct - Ensure the contracts are initialized with the correct admin
- This is expected if testing with the same challengeId twice
- Use a unique challengeId for each test
- The contract prevents duplicate rewards (this is correct behavior)
- Wait 1 minute and try again
- Increase
RATE_LIMIT_MAX_REQUESTSin.envfor testing - Consider implementing a proper rate limiter for production
- Stellar testnet can be slow sometimes
- The API waits up to 30 seconds
- If timeout occurs, check the transaction on Stellar Expert
Awards XP tokens for quiz completion.
Request:
{
"userPublicKey": "GXXXXXX...",
"challengeId": "unique-challenge-id",
"correct": 8,
"total": 10,
"maxXp": 100
}Response:
{
"success": true,
"hash": "transaction-hash",
"xpRewarded": 80,
"message": "Successfully rewarded 80 XP..."
}Mints an NFT badge for module completion.
Request:
{
"userPublicKey": "GXXXXXX...",
"moduleId": "unique-module-id",
"moduleTitle": "DeFi Fundamentals",
"xpEarned": 250,
"quizScore": 85
}Response:
{
"success": true,
"hash": "transaction-hash",
"tokenId": 1,
"message": "Successfully minted badge..."
}For production, consider using Redis:
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
});
async function checkRateLimit(key: string): Promise<boolean> {
const count = await redis.incr(key);
if (count === 1) {
await redis.expire(key, 60); // 60 seconds
}
return count <= 10; // max 10 requests per minute
}Add database logging for auditing:
// After successful transaction
await db.transaction.create({
hash: txHash,
userPublicKey,
type: "REWARD_QUIZ",
challengeId,
xpRewarded,
timestamp: new Date(),
});Set up alerts for:
- Failed transactions
- Rate limit violations
- High transaction fees
- Low admin account balance
- API Documentation: See
src/app/api/README.md - Example Component: See
src/components/examples/QuizCompletionExample.tsx - Stellar Docs: https://developers.stellar.org/
- Soroban Docs: https://soroban.stellar.org/
- Next.js API Routes: https://nextjs.org/docs/api-routes/introduction
- ✅ Set up environment variables
- ✅ Test endpoints locally
- ✅ Integrate into frontend components
- ✅ Deploy to Vercel
- ✅ Test production endpoints
- 🎯 Add monitoring and logging
- 🎯 Implement persistent rate limiting
- 🎯 Add admin dashboard for monitoring