Store transaction signatures in level DB

This commit is contained in:
Adw8 2025-01-27 17:55:09 +05:30
parent 6e6c10edc1
commit 6e39f156d5
4 changed files with 316 additions and 8 deletions

285
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",
"level": "^7.0.0",
"next": "13.5.4",
"openai": "^4.77.0",
"react": "^18",
@ -930,6 +931,24 @@
"node": ">=6.5"
}
},
"node_modules/abstract-leveldown": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz",
"integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"buffer": "^6.0.3",
"catering": "^2.0.0",
"is-buffer": "^2.0.5",
"level-concat-iterator": "^3.0.0",
"level-supports": "^2.0.1",
"queue-microtask": "^1.2.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
@ -1561,6 +1580,15 @@
}
]
},
"node_modules/catering": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz",
"integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/chalk": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.0.tgz",
@ -1768,6 +1796,20 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
"node_modules/deferred-leveldown": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-7.0.0.tgz",
"integrity": "sha512-QKN8NtuS3BC6m0B8vAnBls44tX1WXAFATUsJlruyAYbZpysWV3siH6o/i3g9DCHauzodksO60bdj5NazNbjCmg==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"abstract-leveldown": "^7.2.0",
"inherits": "^2.0.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@ -1889,6 +1931,22 @@
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
"dev": true
},
"node_modules/encoding-down": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.1.0.tgz",
"integrity": "sha512-ky47X5jP84ryk5EQmvedQzELwVJPjCgXDQZGeb9F6r4PdChByCGHTBrVcF3h8ynKVJ1wVbkxTsDC8zBROPypgQ==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"abstract-leveldown": "^7.2.0",
"inherits": "^2.0.3",
"level-codec": "^10.0.0",
"level-errors": "^3.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
@ -3255,8 +3313,7 @@
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/internal-slot": {
"version": "1.1.0",
@ -3347,6 +3404,29 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-buffer": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/is-bun-module": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.3.0.tgz",
@ -3883,6 +3963,144 @@
"node": ">=0.10"
}
},
"node_modules/level": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/level/-/level-7.0.1.tgz",
"integrity": "sha512-w3E64+ALx2eZf8RV5JL4kIcE0BFAvQscRYd1yU4YVqZN9RGTQxXSvH202xvK15yZwFFxRXe60f13LJjcJ//I4Q==",
"license": "MIT",
"dependencies": {
"level-js": "^6.1.0",
"level-packager": "^6.0.1",
"leveldown": "^6.1.0"
},
"engines": {
"node": ">=10.12.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/level"
}
},
"node_modules/level-codec": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz",
"integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==",
"deprecated": "Superseded by level-transcoder (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"buffer": "^6.0.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/level-concat-iterator": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz",
"integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"catering": "^2.1.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/level-errors": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.1.tgz",
"integrity": "sha512-tqTL2DxzPDzpwl0iV5+rBCv65HWbHp6eutluHNcVIftKZlQN//b6GEnZDM2CvGZvzGYMwyPtYppYnydBQd2SMQ==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/level-iterator-stream": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz",
"integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/level-js": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/level-js/-/level-js-6.1.0.tgz",
"integrity": "sha512-i7mPtkZm68aewfv0FnIUWvFUFfoyzIvVKnUmuQGrelEkP72vSPTaA1SGneWWoCV5KZJG4wlzbJLp1WxVNGuc6A==",
"deprecated": "Superseded by browser-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"abstract-leveldown": "^7.2.0",
"buffer": "^6.0.3",
"inherits": "^2.0.3",
"ltgt": "^2.1.2",
"run-parallel-limit": "^1.1.0"
}
},
"node_modules/level-packager": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.1.tgz",
"integrity": "sha512-8Ezr0XM6hmAwqX9uu8IGzGNkWz/9doyPA8Oo9/D7qcMI6meJC+XhIbNYHukJhIn8OGdlzQs/JPcL9B8lA2F6EQ==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"encoding-down": "^7.1.0",
"levelup": "^5.1.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/level-supports": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz",
"integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==",
"license": "MIT",
"engines": {
"node": ">=10"
}
},
"node_modules/leveldown": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.1.tgz",
"integrity": "sha512-88c+E+Eizn4CkQOBHwqlCJaTNEjGpaEIikn1S+cINc5E9HEvJ77bqY4JY/HxT5u0caWqsc3P3DcFIKBI1vHt+A==",
"deprecated": "Superseded by classic-level (https://github.com/Level/community#faq)",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"abstract-leveldown": "^7.2.0",
"napi-macros": "~2.0.0",
"node-gyp-build": "^4.3.0"
},
"engines": {
"node": ">=10.12.0"
}
},
"node_modules/levelup": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/levelup/-/levelup-5.1.1.tgz",
"integrity": "sha512-0mFCcHcEebOwsQuk00WJwjLI6oCjbBuEYdh/RaRqhjnyVlzqf41T1NnDtCedumZ56qyIh8euLFDqV1KfzTAVhg==",
"deprecated": "Superseded by abstract-level (https://github.com/Level/community#faq)",
"license": "MIT",
"dependencies": {
"catering": "^2.0.0",
"deferred-leveldown": "^7.0.0",
"level-errors": "^3.0.1",
"level-iterator-stream": "^5.0.0",
"level-supports": "^2.0.1",
"queue-microtask": "^1.2.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -3949,6 +4167,12 @@
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
"dev": true
},
"node_modules/ltgt": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
"integrity": "sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==",
"license": "MIT"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -4065,6 +4289,12 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/napi-macros": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz",
"integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==",
"license": "MIT"
},
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@ -4157,7 +4387,6 @@
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
@ -4707,7 +4936,6 @@
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
@ -4761,6 +4989,20 @@
"pify": "^2.3.0"
}
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@ -4968,6 +5210,29 @@
"queue-microtask": "^1.2.2"
}
},
"node_modules/run-parallel-limit": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz",
"integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT",
"dependencies": {
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-array-concat": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
@ -5211,6 +5476,15 @@
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/string-width": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@ -5871,8 +6145,7 @@
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/uuid": {
"version": "8.3.2",

View File

@ -16,7 +16,8 @@
"next": "13.5.4",
"openai": "^4.77.0",
"react": "^18",
"react-dom": "^18"
"react-dom": "^18",
"level": "^7.0.0"
},
"devDependencies": {
"@types/node": "^20",

View File

@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from 'next/server'
import { fal } from "@fal-ai/client"
import { FLUX_MODELS } from '../../../services/fluxService'
import { verifyPayment } from '../../../utils/verifyPayment'
import { verifyPayment, isSignatureUsed, markSignatureAsUsed } from '../../../utils/verifyPayment'
if (!process.env.FAL_AI_KEY) {
throw new Error('FAL_AI_KEY is not configured in environment variables')
@ -35,6 +35,13 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
)
}
if (await isSignatureUsed(transactionSignature)) {
return NextResponse.json(
{ error: 'Transaction signature has already been used' },
{ status: 400 }
)
}
const model = FLUX_MODELS.find((model) => model.modelId === modelId)
if (!model) {
return NextResponse.json(
@ -50,6 +57,8 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
throw new Error('Payment verification failed');
}
await markSignatureAsUsed(transactionSignature)
console.log('Generating with Flux model:', modelId)
console.log('Prompt:', prompt)

View File

@ -1,9 +1,13 @@
import level from 'level';
import { Connection } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
const SOLANA_WEBSOCKET_URL = process.env.NEXT_PUBLIC_SOLANA_WEBSOCKET_URL;
const db = level('./usedSignaturesDB');
const connection = new Connection(
SOLANA_RPC_URL,
{
@ -13,11 +17,32 @@ const connection = new Connection(
}
);
export async function isSignatureUsed(transactionSignature: string): Promise<boolean> {
try {
await db.get(transactionSignature);
return true;
} catch (error) {
if (error.notFound) {
return false;
}
throw error;
}
}
export async function markSignatureAsUsed(transactionSignature: string): Promise<void> {
await db.put(transactionSignature, 'used');
}
export async function verifyPayment(
transactionSignature: string,
expectedAmount: number,
): Promise<boolean> {
try {
// Check if the signature is already used
if (await isSignatureUsed(transactionSignature)) {
return false;
}
const transaction = await connection.getParsedTransaction(transactionSignature, 'finalized');
if (!transaction) {
throw new Error('Transaction not found');