Add gorbagana chain ID

This commit is contained in:
Shreerang Kale 2025-08-07 14:49:48 +05:30
parent ed08ace0a4
commit 5e405c03db
2 changed files with 23 additions and 19 deletions

View File

@ -3,7 +3,7 @@ import { NextRequest, NextResponse } from 'next/server';
import axios from 'axios'; import axios from 'axios';
import assert from 'assert'; import assert from 'assert';
import { Connection } from '@solana/web3.js'; import { Connection, ParsedTransactionWithMeta } from '@solana/web3.js';
import { verifyUnusedSolanaPayment } from '@/utils/solana-verify'; import { verifyUnusedSolanaPayment } from '@/utils/solana-verify';
import { transferLNTTokens } from '@/services/laconic-transfer'; import { transferLNTTokens } from '@/services/laconic-transfer';
@ -25,6 +25,7 @@ const ALLOWED_SLIPPAGE_FACTOR = 0.2
// Use CAIP convention for chain ID: namespace + reference // Use CAIP convention for chain ID: namespace + reference
const SOLANA_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'; // Solana mainnet const SOLANA_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'; // Solana mainnet
const GORBAGANA_CHAIN_ID = 'gorbagana:533uBE9RRquhTBqEX58oV52FdTTsReMd' // Gorbagana chain (first 32 characters of gorbagana genesis hash. Following solana CAIP chain ID pattern)
// Sleep helper function // Sleep helper function
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
@ -167,6 +168,7 @@ export async function POST(request: NextRequest) {
// First check if the request body is valid JSON // First check if the request body is valid JSON
let url, txHash, senderPublicKey, paymentMethod; let url, txHash, senderPublicKey, paymentMethod;
let connection: Connection; let connection: Connection;
let parsedTx: ParsedTransactionWithMeta | null;
try { try {
const body = await request.json(); const body = await request.json();
@ -186,6 +188,8 @@ export async function POST(request: NextRequest) {
}, { status: 400 }); }, { status: 400 });
} }
parsedTx = tx;
const signerKeys = tx.transaction.message.accountKeys const signerKeys = tx.transaction.message.accountKeys
.filter(k => k.signer) .filter(k => k.signer)
.map(k => k.pubkey.toBase58()); .map(k => k.pubkey.toBase58());
@ -243,9 +247,13 @@ export async function POST(request: NextRequest) {
const requiredAmountInBaseUnits = requiredTokenInfo.requiredAmountInBaseUnits; const requiredAmountInBaseUnits = requiredTokenInfo.requiredAmountInBaseUnits;
const expectedTokenAmount = Math.round(requiredAmountInBaseUnits - ALLOWED_SLIPPAGE_FACTOR * requiredAmountInBaseUnits); const expectedTokenAmount = Math.round(requiredAmountInBaseUnits - ALLOWED_SLIPPAGE_FACTOR * requiredAmountInBaseUnits);
if (!parsedTx) {
throw new Error(`Unable to find the tx with hash: ${txHash}`)
}
const solanaPaymentResult = await verifyUnusedSolanaPayment( const solanaPaymentResult = await verifyUnusedSolanaPayment(
connection, connection,
txHash, parsedTx,
new BN(expectedTokenAmount), new BN(expectedTokenAmount),
paymentMethod, paymentMethod,
); );
@ -457,7 +465,7 @@ export async function POST(request: NextRequest) {
repository_ref: fullHash, repository_ref: fullHash,
}, },
external_payment: { external_payment: {
chain_id: SOLANA_CHAIN_ID, chain_id: paymentMethod === PaymentMethod.SPL_TOKEN ? SOLANA_CHAIN_ID : GORBAGANA_CHAIN_ID,
tx_hash: txHash, tx_hash: txHash,
pubkey: senderPublicKey pubkey: senderPublicKey
}, },
@ -516,4 +524,4 @@ export async function POST(request: NextRequest) {
message: error instanceof Error ? error.message : 'Unknown error', message: error instanceof Error ? error.message : 'Unknown error',
}, { status: 500 }); }, { status: 500 });
} }
} }

View File

@ -1,6 +1,6 @@
import BN from 'bn.js'; import BN from 'bn.js';
import { Connection, ParsedInstruction, PartiallyDecodedInstruction } from '@solana/web3.js'; import { Connection, ParsedInstruction, ParsedTransactionWithMeta, PartiallyDecodedInstruction } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { getRecipientAddress } from '@/services/solana'; import { getRecipientAddress } from '@/services/solana';
@ -8,13 +8,11 @@ import { PaymentMethod } from '../types';
// Extract transaction info for native GOR transfers // Extract transaction info for native GOR transfers
const extractTxInfo = async ( const extractTxInfo = async (
connection: Connection, parsedTx: ParsedTransactionWithMeta,
transactionSignature: string,
paymentMethod: PaymentMethod paymentMethod: PaymentMethod
): Promise<{ authority: string; amount: string; destination: string }> => { ): Promise<{ authority: string; amount: string; destination: string }> => {
const result = await connection.getParsedTransaction(transactionSignature, 'confirmed');
if (!result) { if (!parsedTx) {
throw new Error('Transaction not found'); throw new Error('Transaction not found');
} }
@ -23,7 +21,7 @@ const extractTxInfo = async (
switch (paymentMethod) { switch (paymentMethod) {
case PaymentMethod.NAT_GOR: case PaymentMethod.NAT_GOR:
// Look for system program transfer instruction // Look for system program transfer instruction
transferInstruction = result.transaction.message.instructions.find( transferInstruction = parsedTx.transaction.message.instructions.find(
(instr) => 'parsed' in instr && instr.parsed.type === 'transfer' (instr) => 'parsed' in instr && instr.parsed.type === 'transfer'
); );
@ -36,7 +34,7 @@ const extractTxInfo = async (
case PaymentMethod.SPL_TOKEN: case PaymentMethod.SPL_TOKEN:
// Look for token transfer instruction using TOKEN_PROGRAM_ID // Look for token transfer instruction using TOKEN_PROGRAM_ID
transferInstruction = result.transaction.message.instructions.find( transferInstruction = parsedTx.transaction.message.instructions.find(
(instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID) (instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID)
); );
@ -68,7 +66,7 @@ const extractTxInfo = async (
export const verifyUnusedSolanaPayment = async ( export const verifyUnusedSolanaPayment = async (
connection: Connection, connection: Connection,
transactionSignature: string, parsedTx: ParsedTransactionWithMeta,
expectedAmount: BN, expectedAmount: BN,
paymentMethod: PaymentMethod, paymentMethod: PaymentMethod,
): Promise<{ ): Promise<{
@ -81,9 +79,7 @@ export const verifyUnusedSolanaPayment = async (
// TODO: Check if provided signature is already used // TODO: Check if provided signature is already used
// Fetch transaction details // Fetch transaction details
const transactionResult = await connection.getParsedTransaction(transactionSignature, 'confirmed'); if (!parsedTx) {
if (!transactionResult) {
return { return {
valid: false, valid: false,
reason: 'Transaction not found on Solana blockchain' reason: 'Transaction not found on Solana blockchain'
@ -91,15 +87,15 @@ export const verifyUnusedSolanaPayment = async (
} }
// Check if transaction was successful // Check if transaction was successful
if (transactionResult.meta?.err) { if (parsedTx.meta?.err) {
return { return {
valid: false, valid: false,
reason: `Transaction failed: ${JSON.stringify(transactionResult.meta.err)}` reason: `Transaction failed: ${JSON.stringify(parsedTx.meta.err)}`
}; };
} }
// Check transaction timestamp (5-minute window) // Check transaction timestamp (5-minute window)
const txTimestamp = transactionResult.blockTime ? new Date(transactionResult.blockTime * 1000) : null; const txTimestamp = parsedTx.blockTime ? new Date(parsedTx.blockTime * 1000) : null;
if (!txTimestamp) { if (!txTimestamp) {
return { return {
valid: false, valid: false,
@ -119,7 +115,7 @@ export const verifyUnusedSolanaPayment = async (
} }
// Extract transaction info based on payment method // Extract transaction info based on payment method
const transferInfo = await extractTxInfo(connection, transactionSignature, paymentMethod); const transferInfo = await extractTxInfo(parsedTx, paymentMethod);
const amount = transferInfo.amount; const amount = transferInfo.amount;
const authority = transferInfo.authority; const authority = transferInfo.authority;
const destination = transferInfo.destination; const destination = transferInfo.destination;