sol-mem-gen/src/app/api/lock/route.ts
2025-02-06 18:13:51 +05:30

173 lines
6.0 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { Connection, Keypair, ParsedInstruction, ParsedTransactionWithMeta, PartiallyDecodedInstruction, PublicKey } from "@solana/web3.js";
import { createLock } from "../../../utils/create-lock";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import assert from "assert";
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
import { BN, min } from "bn.js";
assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL);
const connection = new Connection(process.env.NEXT_PUBLIC_SOLANA_RPC_URL);
const MTM_MINT_ADDRESS = process.env.NEXT_PUBLIC_MTM_TOKEN_MINT;
function isParsedInstruction(
instruction: ParsedInstruction | PartiallyDecodedInstruction
): instruction is ParsedInstruction {
return (instruction as ParsedInstruction).parsed !== undefined;
}
async function extractMTMTransferDetails(
connection: Connection,
signature: string,
mtmMintAddress: string // Mint address of the MTM token
) {
try {
// Fetch the transaction details using the signature
const transaction: ParsedTransactionWithMeta | null = await connection.getParsedTransaction(signature, {
maxSupportedTransactionVersion: 0, // Ensure compatibility with legacy transactions
});
if (!transaction) {
throw new Error('Transaction not found');
}
// Extract the "from", "to", and "amount" for the MTM token transfer
let fromAddress: string | null = null;
let toAddress: string | null = null;
let tokenAmount: number | null = null;
// Function to process instructions
const processInstructions = (instructions: ParsedInstruction[]) => {
instructions.forEach((instruction: ParsedInstruction) => {
if (instruction.programId.equals(new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'))) {
// Check if the instruction is a transfer instruction
if (instruction.parsed.type === 'transfer' || instruction.parsed.type === 'transferChecked') {
const parsedInfo = instruction.parsed.info;
const mint = parsedInfo.mint;
// Check if the mint address matches the provided MTM mint address
if (mint === mtmMintAddress) {
fromAddress = parsedInfo.source;
toAddress = parsedInfo.destination;
tokenAmount = parsedInfo.amount;
}
}
}
});
};
// Filter out PartiallyDecodedInstruction and process only ParsedInstruction
const parsedInstructions = transaction.transaction.message.instructions.filter(isParsedInstruction);
// Process top-level instructions
processInstructions(parsedInstructions);
// Process inner instructions (if any)
if (transaction.meta?.innerInstructions) {
transaction.meta.innerInstructions.forEach((inner) => {
const innerParsedInstructions = inner.instructions.filter(isParsedInstruction);
processInstructions(innerParsedInstructions);
});
}
if (!fromAddress || !toAddress || !tokenAmount) {
throw new Error('No matching MTM token transfer found in the transaction');
}
return { fromAddress, toAddress, tokenAmount };
} catch (error) {
console.error('Error extracting MTM transfer details:', error);
throw error;
}
}
export async function GET(req: NextRequest) {
try {
// Get signature from URL params
const { searchParams } = new URL(req.url);
const signature = searchParams.get('signature') || '4HBtnoNUuMGpmbhD9cPiJtbxkhux31pfZs3HYud5eopAU69RaC4UbJsYdj83eafFxV6eH8pSaRgqELrwyjrWp7yz';
let amount = new BN(0);
if (!signature) {
return NextResponse.json(
{ error: "Transaction signature is required" },
{ status: 400 }
);
}
if (!MTM_MINT_ADDRESS) {
return NextResponse.json(
{ error: "MTM_MINT_ADDRESS environment variable is not set" },
{ status: 500 }
);
}
// Extract transaction details
// const result = await extractMTMTransferDetails(
// connection,
// signature,
// MTM_MINT_ADDRESS
// );
// if (!result) {
// return NextResponse.json(
// { error: "Failed to extract transaction details" },
// { status: 500 }
// );
// }
// console.log({ result });
// // Validate extracted values
// if (!result.fromAddress || result.tokenAmount <= 0) {
// return NextResponse.json(
// { error: "Invalid transaction details extracted" },
// { status: 400 }
// );
// }
assert(process.env.USER_PRIVATE_KEY, 'USER_PRIVATE_KEY is required');
assert(process.env.CLIFF_TIME, 'CLIFF_TIME is required');
const USER_PRIVATE_KEY = process.env.USER_PRIVATE_KEY;
const CLIFF_TIME = process.env.CLIFF_TIME;
const duration = new BN(CLIFF_TIME).add(new BN(Math.floor(Date.now() / 1000)));
const tokenLockerKeypair = Keypair.fromSecretKey(bs58.decode(USER_PRIVATE_KEY));
const recipientPublicKey = new PublicKey('Bnnq8n3rRKZe8NJAYn4vBkxp1v8Bnc6zXpUPpDeujCu');
amount = amount.add(new BN(1000000));
// Call createLock function with extracted values
let escrow;
try {
escrow = await createLock(tokenLockerKeypair, recipientPublicKey, duration, amount);
} catch (error) {
console.error('Error creating lock:', error);
return NextResponse.json(
{ error: "Failed to create lock" },
{ status: 500 }
);
}
console.log({ escrow });
// Return successful response
return NextResponse.json({
success: true,
data: {
sender: recipientPublicKey,
amount: amount,
}
});
} catch (error) {
console.error('API route error:', error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}