forked from mito-systems/sol-mem-gen
Use backend cache for getting quotes during payment verification
This commit is contained in:
parent
f712adfec2
commit
ddda589da9
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<NextResponse> {
|
||||
)
|
||||
}
|
||||
|
||||
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 }
|
||||
)
|
||||
}
|
||||
|
@ -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 });
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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'
|
||||
}
|
||||
|
@ -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<BN> {
|
||||
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 }>
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export async function markSignatureAsUsed(transactionSignature: string): Promise
|
||||
|
||||
export async function verifyPayment(
|
||||
transactionSignature: string,
|
||||
expectedAmount: BN,
|
||||
lowestQuote: BN,
|
||||
): Promise<boolean> {
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user