Create lock on every fourth twitter post

This commit is contained in:
Adw8 2025-02-06 12:07:00 +05:30
parent df914a7f39
commit 30e906bb14
4 changed files with 55 additions and 54 deletions

View File

@ -1,52 +1,9 @@
import { NextRequest, NextResponse } from "next/server";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { createLock } from "../../../utils/create-lock";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
import { BN } from "bn.js";
import Big from 'big.js';
import { Connection} from "@solana/web3.js";
import { createRewardLock, extractInfo } from "../../../utils/create-lock";
const connection = new Connection(process.env.NEXT_PUBLIC_SOLANA_RPC_URL!);
async function extractInfo(transactionSignature: string) {
const transaction = await connection.getParsedTransaction(transactionSignature, 'confirmed');
if (!transaction) {
throw new Error('Transaction not found');
}
const transferInstruction = transaction.transaction.message.instructions.find(
(instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID)
);
if (!transferInstruction || !('parsed' in transferInstruction)) {
throw new Error('Transfer instruction not found');
}
const { info: { amount, authority } } = transferInstruction.parsed;
return { authority, amount };
}
async function createRewardLock(authority: string, amount: string) {
const { WSOL_LOCKER_PRIVATE_KEY, CLIFF_TIME, WSOL_MINT, NEXT_PUBLIC_MTM_TOKEN_MINT, REWARD_MULTIPLIER } = process.env;
if (!WSOL_LOCKER_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(WSOL_LOCKER_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 {
const { searchParams } = new URL(req.url);

View File

@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { saveTweet, verifySignatureInTweet } from '../../../utils/verifyTweet';
import { createRewardLock, extractInfo } from '../../../utils/create-lock';
export async function POST(req: NextRequest): Promise<NextResponse> {
try {
@ -30,8 +31,17 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
}
const { isFourthUser } = await saveTweet({ transactionSignature: txSignature, url: memeUrl });
if (isFourthUser) {
createTokenLockForRecipient();
const { authority, amount } = await extractInfo(txSignature);
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 } });
}
return NextResponse.json({ success: isVerified, message: 'Tweet verified' })
@ -59,8 +69,3 @@ const extractData = (tweet: string | object) => {
handle: handleMatch ? handleMatch[1] : null,
};
};
// TODO: Implement function to create lock for a recipient
const createTokenLockForRecipient = () => {
console.log('Lock created');
}

View File

@ -2,12 +2,13 @@ import assert from 'assert';
import BN from 'bn.js';
import 'dotenv/config';
import bs58 from 'bs58';
import Big from 'big.js';
import * as anchor from "@coral-xyz/anchor";
import {
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import { Connection, PublicKey } from "@solana/web3.js";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
import { createVestingPlanV2 } from '../locker-utils';
@ -64,3 +65,42 @@ export async function createLock(tokenLockerKeypair: anchor.web3.Keypair, recipi
return escrow;
}
export async function extractInfo(transactionSignature: string) {
const transaction = await connection.getParsedTransaction(transactionSignature, 'confirmed');
if (!transaction) {
throw new Error('Transaction not found');
}
const transferInstruction = transaction.transaction.message.instructions.find(
(instr) => 'parsed' in instr && instr.programId.equals(TOKEN_PROGRAM_ID)
);
if (!transferInstruction || !('parsed' in transferInstruction)) {
throw new Error('Transfer instruction not found');
}
const { info: { amount, authority } } = transferInstruction.parsed;
return { authority, amount };
}
export async function createRewardLock(authority: string, amount: string) {
const { WSOL_LOCKER_PRIVATE_KEY, CLIFF_TIME, WSOL_MINT, NEXT_PUBLIC_MTM_TOKEN_MINT, REWARD_MULTIPLIER } = process.env;
if (!WSOL_LOCKER_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(WSOL_LOCKER_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);
}

View File

@ -4,8 +4,6 @@ import BN from 'bn.js';
import { Connection } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { Payment } from '../entity/Payment';
assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required');
const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
@ -44,6 +42,7 @@ export async function markSignatureAsUsed(transactionSignature: string): Promise
});
}
// TODO: Verify that payment receiver is correct
export async function verifyPayment(
transactionSignature: string,
tokenAmount: BN,