Use big.js for handling decimals

This commit is contained in:
Adw8 2025-01-30 14:41:29 +05:30
parent cc64e6a035
commit 2e735c51dd
9 changed files with 39 additions and 19 deletions

14
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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);
}

View File

@ -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

View File

@ -48,13 +48,13 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
}
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(

View File

@ -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}

View File

@ -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<AIServiceCardProps> = ({
@ -64,6 +65,8 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
setTimeout(() => {
window.location.reload();
}, 3000);
return
}
if (result.imageUrl) {
@ -124,7 +127,7 @@ const AIServiceCard: React.FC<AIServiceCardProps> = ({
{generationState.error && (
<div className="mt-4 bg-red-900/20 border border-red-500/20 text-red-400 px-4 py-3 rounded-xl text-center">
{generationState.error}, reloading...
{generationState.error}
</div>
)}

View File

@ -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()

View File

@ -47,7 +47,7 @@ export async function markSignatureAsUsed(transactionSignature: string): Promise
export async function verifyPayment(
transactionSignature: string,
lowestQuote: BN,
tokenAmount: BN,
): Promise<boolean> {
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');