From 2e735c51dd0f42239d61c41194a2f16b9a10f8fb Mon Sep 17 00:00:00 2001 From: Adw8 Date: Thu, 30 Jan 2025 14:41:29 +0530 Subject: [PATCH] Use big.js for handling decimals --- package-lock.json | 14 ++++++++++++++ package.json | 1 + quotes-service.ts | 8 +++++--- server.ts | 4 +++- src/app/api/flux/route.ts | 6 +++--- src/app/page.tsx | 1 - src/components/AIServiceCard.tsx | 17 ++++++++++------- src/services/fluxService.ts | 2 +- src/utils/verifyPayment.ts | 5 ++--- 9 files changed, 39 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index e286f6a..127b13e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@google/generative-ai": "^0.21.0", "@solana/spl-token": "^0.3.8", "@solana/web3.js": "^1.78.4", + "big.js": "^6.2.2", "bn.js": "^5.2.0", "dotenv": "^16.4.7", "next": "13.5.4", @@ -1501,6 +1502,19 @@ } ] }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, "node_modules/bigint-buffer": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", diff --git a/package.json b/package.json index ba3c441..48b3908 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@google/generative-ai": "^0.21.0", "@solana/spl-token": "^0.3.8", "@solana/web3.js": "^1.78.4", + "big.js": "^6.2.2", "bn.js": "^5.2.0", "dotenv": "^16.4.7", "next": "13.5.4", diff --git a/quotes-service.ts b/quotes-service.ts index 9ff7481..bfdb871 100644 --- a/quotes-service.ts +++ b/quotes-service.ts @@ -1,6 +1,7 @@ import assert from "assert"; import BN from "bn.js"; import fetch from 'node-fetch'; +import Big from 'big.js'; assert(process.env.NEXT_PUBLIC_USDC_MINT, 'USDC_MINT is required'); assert(process.env.NEXT_PUBLIC_MTM_TOKEN_MINT, 'MTM_TOKEN_MINT is required'); @@ -21,14 +22,15 @@ class QuotesService { } const quoteResponse = await response.json(); - const priceFromAPI = Number(quoteResponse['data'][USDC_MINT]['price']).toFixed(6); - const price = new BN(priceFromAPI.toString().replace('.', '')); + + // Handle price with Big.js, then convert to BN + const priceFromAPI = new Big(quoteResponse['data'][USDC_MINT]['price']).toFixed(6); + const price = new BN(new Big(priceFromAPI).times(new Big(10).pow(6)).toString()); this.cachedQuotes.push(price); if (this.cachedQuotes.length > 3) { this.cachedQuotes.shift(); } - console.log('Cache updated: ', this.cachedQuotes); } catch (error) { console.error('Error fetching quotes:', error); } diff --git a/server.ts b/server.ts index dcba014..8ee34d4 100644 --- a/server.ts +++ b/server.ts @@ -1,6 +1,8 @@ import { createServer } from 'http'; import { parse } from 'url'; import next from 'next'; + +// Reference: https://www.dotenv.org/docs/quickstart#initial-setup import dotenv from 'dotenv'; dotenv.config(); @@ -16,9 +18,9 @@ declare global { namespace NodeJS { interface Global { quotesService: typeof quotesService + } } } -} // TODO: Look for a better way to use quotesService // Initialize global quotes service diff --git a/src/app/api/flux/route.ts b/src/app/api/flux/route.ts index 0d90b55..8b7601d 100644 --- a/src/app/api/flux/route.ts +++ b/src/app/api/flux/route.ts @@ -48,13 +48,13 @@ export async function POST(req: NextRequest): Promise { } const quotes: BN[] = (global as any).quotesService.getQuotes(); - const priceMTMFor1USDC = quotes.reduce((min, quote) => quote.lt(min) ? quote : min, quotes[0]); // Take the minimum quote from the array + const lowestQuote = quotes.reduce((minQuote, currentQuote) => BN.min(minQuote, currentQuote), quotes[0]); const scale = new BN(100); const scaledCost = new BN(model.cost * 100); - const lowestQuote = scaledCost.mul(new BN(priceMTMFor1USDC)).div(scale); - const isPaymentVerified = await verifyPayment(transactionSignature, lowestQuote); + const tokenAmount = scaledCost.mul(new BN(lowestQuote)).div(scale); + const isPaymentVerified = await verifyPayment(transactionSignature, tokenAmount); if (!isPaymentVerified) { return NextResponse.json( diff --git a/src/app/page.tsx b/src/app/page.tsx index 0a1461c..a147ef1 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -132,7 +132,6 @@ const Page: React.FC = (): React.ReactElement => { isWalletConnected={walletState.connected} onGenerate={handleFluxGeneration( model.modelId, - // Calculate scaled cost directly in bn.js priceMTM )} priceMTM={priceMTM} diff --git a/src/components/AIServiceCard.tsx b/src/components/AIServiceCard.tsx index 52ddfef..547b8bd 100644 --- a/src/components/AIServiceCard.tsx +++ b/src/components/AIServiceCard.tsx @@ -2,6 +2,7 @@ import React, { useState } from 'react' import BN from 'bn.js'; +import Big from 'big.js'; interface AIServiceCardProps { title: string @@ -19,12 +20,12 @@ interface GenerationState { } const formatBNWithDecimals = (value: BN, decimals: number): string => { - const factor = new BN(10).pow(new BN(decimals)); - // Part before decimal point - const quotient = value.div(factor); - // Part after decimal point - const remainder = value.mod(factor); - return `${quotient.toString()}.${remainder.toString().padStart(decimals, '0')}`; + if (value.isZero()) return '0.' + '0'.repeat(decimals); // Handle zero case + + const bigValue = new Big(value.toString()); + const factor = new Big(10).pow(decimals); + + return bigValue.div(factor).toFixed(decimals); } const AIServiceCard: React.FC = ({ @@ -64,6 +65,8 @@ const AIServiceCard: React.FC = ({ setTimeout(() => { window.location.reload(); }, 3000); + + return } if (result.imageUrl) { @@ -124,7 +127,7 @@ const AIServiceCard: React.FC = ({ {generationState.error && (
- {generationState.error}, reloading... + {generationState.error}
)} diff --git a/src/services/fluxService.ts b/src/services/fluxService.ts index a947fb0..14c68a0 100644 --- a/src/services/fluxService.ts +++ b/src/services/fluxService.ts @@ -51,7 +51,7 @@ export async function generateWithFlux( }) if (!response.ok) { - throw new Error('Failed to generate image') + throw new Error('Failed to generate image, reloading...') } const data = await response.json() diff --git a/src/utils/verifyPayment.ts b/src/utils/verifyPayment.ts index 145ab21..2b5f91a 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, - lowestQuote: BN, + tokenAmount: BN, ): Promise { try { // Check if the signature is already used @@ -74,8 +74,7 @@ export async function verifyPayment( const transactionAmount = new BN(amount); - if (transactionAmount.gte(lowestQuote)) { - console.log('Transaction amount is greater than minimum amount'); + if (transactionAmount.gte(tokenAmount)) { return true; } console.log('Transaction amount is less than minimum amount. Rejecting request');