Add gorbagana chain ID
This commit is contained in:
parent
ed08ace0a4
commit
5e405c03db
@ -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 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user