From ddda589da95cc40bf7763e034b0e647ad40a6926 Mon Sep 17 00:00:00 2001 From: Adw8 Date: Thu, 30 Jan 2025 11:47:28 +0530 Subject: [PATCH] Use backend cache for getting quotes during payment verification --- quotes-service.ts | 5 ++--- src/app/api/flux/route.ts | 13 ++++++------- src/app/api/quotes/route.ts | 10 ++++++++-- src/app/page.tsx | 5 ++++- src/services/fluxService.ts | 2 ++ src/services/paymentService.ts | 18 ------------------ src/utils/verifyPayment.ts | 10 ++-------- 7 files changed, 24 insertions(+), 39 deletions(-) diff --git a/quotes-service.ts b/quotes-service.ts index 1904eca..9ff7481 100644 --- a/quotes-service.ts +++ b/quotes-service.ts @@ -34,9 +34,8 @@ class QuotesService { } } - getLatestQuote(): BN | undefined { - console.log({ cachedQuotes: this.cachedQuotes }); - return this.cachedQuotes[this.cachedQuotes.length - 1]; + getQuotes(): BN[] { + return this.cachedQuotes; } } diff --git a/src/app/api/flux/route.ts b/src/app/api/flux/route.ts index f3e0734..2da9c52 100644 --- a/src/app/api/flux/route.ts +++ b/src/app/api/flux/route.ts @@ -4,9 +4,7 @@ import BN from 'bn.js'; import { fal } from "@fal-ai/client" import { FLUX_MODELS } from '../../../services/fluxService' import { initializeDataSource } from '../../../data-source' - -import { verifyPayment, markSignatureAsUsed } from '../../../utils/verifyPayment' -import { getUSDCToMTMQuote } from '../../../services/paymentService' +import { verifyPayment, markSignatureAsUsed } from '../../../utils/verifyPayment'; if (!process.env.FAL_AI_KEY) { throw new Error('FAL_AI_KEY is not configured in environment variables') @@ -49,17 +47,18 @@ export async function POST(req: NextRequest): Promise { ) } - const mtmFor1USDC = await getUSDCToMTMQuote(); + const quotes: BN[] = (global as any).quotesService.getQuotes(); + const mtmFor1USDC = quotes.reduce((min, quote) => quote.lt(min) ? quote : min, quotes[0]); // Take the least cost in the array const scale = new BN(100); const scaledCost = new BN(model.cost * 100); - const expectedAmount = scaledCost.mul(mtmFor1USDC).div(scale); - const isPaymentVerified = await verifyPayment(transactionSignature, expectedAmount) + const lowestQuote = scaledCost.mul(new BN(mtmFor1USDC)).div(scale); + const isPaymentVerified = await verifyPayment(transactionSignature, lowestQuote); if (!isPaymentVerified) { return NextResponse.json( - { error: 'Payment verification failed or transaction signature has already been used' }, + { error: 'Payment verification failed or transaction signature has already been used', reload: true }, { status: 400 } ) } diff --git a/src/app/api/quotes/route.ts b/src/app/api/quotes/route.ts index ee8f78d..8ef3744 100644 --- a/src/app/api/quotes/route.ts +++ b/src/app/api/quotes/route.ts @@ -1,6 +1,12 @@ +import BN from 'bn.js'; import { NextRequest, NextResponse } from 'next/server'; export async function GET(req: NextRequest) { - const quote = (global as any).quoteService.getLatestQuote(); - return NextResponse.json(quote); + try { + const quotes: BN[] = (global as any).quotesService.getQuotes(); + const quotesAsString = quotes.map(quote => quote.toString()); + return NextResponse.json(quotesAsString); + } catch (error) { + return NextResponse.json({ error: 'Failed to fetch quotes' }, { status: 500 }); + } } diff --git a/src/app/page.tsx b/src/app/page.tsx index e78ea38..e01cba9 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -24,7 +24,10 @@ const Page: React.FC = (): React.ReactElement => { try { const response = await fetch('/api/quotes'); const data = await response.json(); - setMtmFor1USDC(new BN(data.latestQuote)); // Convert the string back to BN + + // Convert the string back to BN + const price = new BN(data[data.length - 1]); + setMtmFor1USDC(price); } catch (error) { console.error('Failed to fetch price:', error); } diff --git a/src/services/fluxService.ts b/src/services/fluxService.ts index a947fb0..77ec20c 100644 --- a/src/services/fluxService.ts +++ b/src/services/fluxService.ts @@ -65,6 +65,8 @@ export async function generateWithFlux( } } catch (error) { console.error('Flux generation error:', error) + // Reload the page to get latest prices + window.location.reload(); return { error: error instanceof Error ? error.message : 'Generation failed' } diff --git a/src/services/paymentService.ts b/src/services/paymentService.ts index 1adfc9c..6e809a2 100644 --- a/src/services/paymentService.ts +++ b/src/services/paymentService.ts @@ -14,13 +14,11 @@ import { WalletType } from './types' assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required'); assert(process.env.NEXT_PUBLIC_MTM_TOKEN_MINT, 'MTM_TOKEN_MINT is required'); assert(process.env.NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS, 'PAYMENT_RECEIVER_ADDRESS is required'); -assert(process.env.NEXT_PUBLIC_USDC_MINT, 'USDC_MINT is required'); const MTM_TOKEN_MINT = process.env.NEXT_PUBLIC_MTM_TOKEN_MINT; const PAYMENT_RECEIVER_ADDRESS = process.env.NEXT_PUBLIC_PAYMENT_RECEIVER_ADDRESS; const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL; const SOLANA_WEBSOCKET_URL = process.env.NEXT_PUBLIC_SOLANA_WEBSOCKET_URL; -const USDC_MINT = process.env.NEXT_PUBLIC_USDC_MINT; const connection = new Connection( SOLANA_RPC_URL, @@ -51,22 +49,6 @@ async function findAssociatedTokenAddress( )[0] } -export async function getUSDCToMTMQuote(): Promise { - const url = `https://api.jup.ag/price/v2?ids=${USDC_MINT}&vsToken=${MTM_TOKEN_MINT}`; - - const response = await fetch(url); - - if (!response.ok) { - throw new Error(`Failed to fetch quote: ${response.statusText}`); - } - - const quoteResponse = await response.json(); - - const priceFromAPI = Number(quoteResponse['data'][USDC_MINT]['price']).toFixed(6); - const price = new BN(priceFromAPI.toString().replace('.', '')); - return price; -} - interface WalletAdapter { signAndSendTransaction(transaction: Transaction): Promise<{ signature: string }> } diff --git a/src/utils/verifyPayment.ts b/src/utils/verifyPayment.ts index b47e39a..c3427a5 100644 --- a/src/utils/verifyPayment.ts +++ b/src/utils/verifyPayment.ts @@ -47,7 +47,7 @@ export async function markSignatureAsUsed(transactionSignature: string): Promise export async function verifyPayment( transactionSignature: string, - expectedAmount: BN, + lowestQuote: BN, ): Promise { try { // Check if the signature is already used @@ -74,17 +74,11 @@ export async function verifyPayment( const transactionAmount = new BN(amount); - // Transaction amount should be within 10% of the expected amount - const lowerBound = expectedAmount.mul(new BN(9)).div(new BN(10)); - const upperBound = expectedAmount.mul(new BN(11)).div(new BN(10)); - - // transaction within the appropriate range - if (transactionAmount.gte(lowerBound) && transactionAmount.lte(upperBound)) { + if (transactionAmount.gte(lowestQuote)) { console.log('Transaction amount is within the expected range.'); return true; } console.log('Transaction amount is not within the expected range.'); - // TODO: Handle slippage being greater than 10% return false; } catch (error) { console.error('Verification error:', error);