From 8e7c382473d20f93b6f5c228f2204e0f79e39322 Mon Sep 17 00:00:00 2001 From: AdityaSalunkhe21 Date: Wed, 5 Feb 2025 20:12:09 +0530 Subject: [PATCH] Create lock using wsol --- next-env.d.ts | 1 - src/app/api/lock/route.ts | 207 ++++++++++---------------------------- src/utils/create-lock.ts | 8 +- 3 files changed, 55 insertions(+), 161 deletions(-) diff --git a/next-env.d.ts b/next-env.d.ts index fd36f94..4f11a03 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited // see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/src/app/api/lock/route.ts b/src/app/api/lock/route.ts index 422e0ae..fdd607a 100644 --- a/src/app/api/lock/route.ts +++ b/src/app/api/lock/route.ts @@ -1,172 +1,67 @@ import { NextRequest, NextResponse } from "next/server"; -import { Connection, Keypair, ParsedInstruction, ParsedTransactionWithMeta, PartiallyDecodedInstruction, PublicKey } from "@solana/web3.js"; +import { Connection, Keypair, 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"; +import { BN } from "bn.js"; +import Big from 'big.js'; -assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL); +const connection = new Connection(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 extractInfo(transactionSignature: string) { + const transaction = await connection.getParsedTransaction(transactionSignature, 'confirmed'); + if (!transaction) { + throw new Error('Transaction not found'); } -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 - }); + const transferInstruction = transaction.transaction.message.instructions.find( + (instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID) + ); - if (!transaction) { - throw new Error('Transaction not found'); - } + if (!transferInstruction || !('parsed' in transferInstruction)) { + throw new Error('Transfer instruction 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; + const { info: { amount, authority } } = transferInstruction.parsed; + return { authority, amount }; } + +async function createRewardLock(authority: string, amount: string) { + const { USER_PRIVATE_KEY, CLIFF_TIME, WSOL_MINT, NEXT_PUBLIC_MTM_TOKEN_MINT, REWARD_MULTIPLIER } = process.env; + if (!USER_PRIVATE_KEY || !CLIFF_TIME || !WSOL_MINT || !NEXT_PUBLIC_MTM_TOKEN_MINT || !REWARD_MULTIPLIER) { + throw new Error('Missing required environment variables'); + } + + 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(authority); + + const url = `https://api.jup.ag/price/v2?ids=${NEXT_PUBLIC_MTM_TOKEN_MINT}&vsToken=${WSOL_MINT}`; + const response = await fetch(url); + const { data } = await response.json(); + + const priceWSOLFor1MTM = new Big(data[NEXT_PUBLIC_MTM_TOKEN_MINT].price).toFixed(9); + const mtmAmount = new Big(amount).div(new Big(10).pow(6)); + const wsolAmount = new BN(new Big(mtmAmount).times(priceWSOLFor1MTM).times(new Big(10).pow(9)).times(REWARD_MULTIPLIER).toFixed(0)); + + return createLock(tokenLockerKeypair, recipientPublicKey, duration, wsolAmount); } 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); + try { + const { searchParams } = new URL(req.url); + const signature = searchParams.get('signature') || '4HBtnoNUuMGpmbhD9cPiJtbxkhux31pfZs3HYud5eopAU69RaC4UbJsYdj83eafFxV6eH8pSaRgqELrwyjrWp7yz'; - 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 } - ); + const { authority, amount } = await extractInfo(signature); + if (!authority || Number(amount) <= 0) { + return NextResponse.json({ error: "Invalid transaction details" }, { status: 400 }); } -} + + const escrow = await createRewardLock(authority, amount); + return NextResponse.json({ success: true, data: { escrow } }); + + } catch (error) { + console.error('API route error:', error); + return NextResponse.json({ error: "Internal server error" }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/utils/create-lock.ts b/src/utils/create-lock.ts index 8b540f6..ad300a0 100644 --- a/src/utils/create-lock.ts +++ b/src/utils/create-lock.ts @@ -14,16 +14,16 @@ import { createVestingPlanV2 } from '../locker-utils'; assert(process.env.RPC_ENDPOINT); assert(process.env.USER_PRIVATE_KEY); //assert(process.env.RECIPIENT_PUBLIC_KEY); -assert(process.env.MTM_MINT); +assert(process.env.WSOL_MINT); const RPC_ENDPOINT= process.env.RPC_ENDPOINT; -const MTM_MINT = process.env.MTM_MINT; +const WSOL_MINT = process.env.WSOL_MINT; const USER_PRIVATE_KEY = process.env.USER_PRIVATE_KEY; const userKP = anchor.web3.Keypair.fromSecretKey(bs58.decode(USER_PRIVATE_KEY)); const connection = new Connection(RPC_ENDPOINT); -const token = new PublicKey(MTM_MINT); +const token = new PublicKey(WSOL_MINT); const provider = new anchor.AnchorProvider( connection, @@ -35,7 +35,7 @@ const provider = new anchor.AnchorProvider( anchor.setProvider(provider); export async function getMTMBalance (senderKeypair: anchor.web3.Keypair): Promise { - const mintPublicKey = new PublicKey(MTM_MINT); + const mintPublicKey = new PublicKey(WSOL_MINT); const publicKey = senderKeypair.publicKey; const tokenAccounts = await connection.getTokenAccountsByOwner(publicKey, { mint: mintPublicKey });