forked from mito-systems/sol-mem-gen
Create lock on every fourth twitter post
This commit is contained in:
parent
df914a7f39
commit
30e906bb14
@ -1,52 +1,9 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
import { Connection} from "@solana/web3.js";
|
||||||
import { createLock } from "../../../utils/create-lock";
|
import { createRewardLock, extractInfo } 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';
|
|
||||||
|
|
||||||
const connection = new Connection(process.env.NEXT_PUBLIC_SOLANA_RPC_URL!);
|
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) {
|
export async function GET(req: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const { searchParams } = new URL(req.url);
|
const { searchParams } = new URL(req.url);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
import { saveTweet, verifySignatureInTweet } from '../../../utils/verifyTweet';
|
import { saveTweet, verifySignatureInTweet } from '../../../utils/verifyTweet';
|
||||||
|
import { createRewardLock, extractInfo } from '../../../utils/create-lock';
|
||||||
|
|
||||||
export async function POST(req: NextRequest): Promise<NextResponse> {
|
export async function POST(req: NextRequest): Promise<NextResponse> {
|
||||||
try {
|
try {
|
||||||
@ -30,8 +31,17 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { isFourthUser } = await saveTweet({ transactionSignature: txSignature, url: memeUrl });
|
const { isFourthUser } = await saveTweet({ transactionSignature: txSignature, url: memeUrl });
|
||||||
|
|
||||||
if (isFourthUser) {
|
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' })
|
return NextResponse.json({ success: isVerified, message: 'Tweet verified' })
|
||||||
@ -59,8 +69,3 @@ const extractData = (tweet: string | object) => {
|
|||||||
handle: handleMatch ? handleMatch[1] : null,
|
handle: handleMatch ? handleMatch[1] : null,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Implement function to create lock for a recipient
|
|
||||||
const createTokenLockForRecipient = () => {
|
|
||||||
console.log('Lock created');
|
|
||||||
}
|
|
||||||
|
@ -2,12 +2,13 @@ import assert from 'assert';
|
|||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import bs58 from 'bs58';
|
import bs58 from 'bs58';
|
||||||
|
import Big from 'big.js';
|
||||||
|
|
||||||
import * as anchor from "@coral-xyz/anchor";
|
import * as anchor from "@coral-xyz/anchor";
|
||||||
import {
|
import {
|
||||||
TOKEN_PROGRAM_ID,
|
TOKEN_PROGRAM_ID,
|
||||||
} from "@solana/spl-token";
|
} from "@solana/spl-token";
|
||||||
import { Connection, PublicKey } from "@solana/web3.js";
|
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||||
|
|
||||||
import { createVestingPlanV2 } from '../locker-utils';
|
import { createVestingPlanV2 } from '../locker-utils';
|
||||||
|
|
||||||
@ -64,3 +65,42 @@ export async function createLock(tokenLockerKeypair: anchor.web3.Keypair, recipi
|
|||||||
|
|
||||||
return escrow;
|
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);
|
||||||
|
}
|
||||||
|
@ -4,8 +4,6 @@ import BN from 'bn.js';
|
|||||||
import { Connection } from '@solana/web3.js';
|
import { Connection } from '@solana/web3.js';
|
||||||
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
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');
|
assert(process.env.NEXT_PUBLIC_SOLANA_RPC_URL, 'SOLANA_RPC_URL is required');
|
||||||
|
|
||||||
const SOLANA_RPC_URL = process.env.NEXT_PUBLIC_SOLANA_RPC_URL;
|
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(
|
export async function verifyPayment(
|
||||||
transactionSignature: string,
|
transactionSignature: string,
|
||||||
tokenAmount: BN,
|
tokenAmount: BN,
|
||||||
|
Loading…
Reference in New Issue
Block a user