UNPKG

@symmetry-hq/liquidity-sdk

Version:

Exchange functionality using symmetry funds liquidity

204 lines (183 loc) 6.75 kB
import {struct, u8 } from '@coral-xyz/borsh'; import { Wallet } from "@coral-xyz/anchor/dist/cjs/provider"; import { TOKEN_PROGRAM_ID, createAssociatedTokenAccountInstruction, createCloseAccountInstruction, getAssociatedTokenAddressSync } from "@solana/spl-token"; import { Connection, PublicKey, SystemProgram, Transaction, TransactionInstruction, } from "@solana/web3.js"; import { TokenSettings, RouteData } from "./types"; export async function applyBlockHashAndPartialSign( connection: Connection, wallet: Wallet, preTransaction:Transaction, transaction:Transaction, postTransaction:Transaction, preSigners:Array<any>, signers:Array<any> ) { let { blockhash } = await connection.getRecentBlockhash('processed'); let result: any = []; let txIndex = 0; if (preTransaction.instructions.length > 0) { txIndex = 1; preTransaction.recentBlockhash = blockhash; preTransaction.feePayer = wallet.publicKey; preTransaction.setSigners(wallet.publicKey, ...preSigners.map((s) => s.publicKey)) if (preSigners.length > 0) preTransaction.partialSign(...preSigners); result.push(preTransaction); } transaction.recentBlockhash = blockhash; transaction.feePayer = wallet.publicKey; transaction.setSigners(wallet.publicKey, ...signers.map((s) => s.publicKey)) if (signers.length > 0) transaction.partialSign(...signers); result.push(transaction); if (postTransaction.instructions.length > 0) { postTransaction.recentBlockhash = blockhash; postTransaction.feePayer = wallet.publicKey; postTransaction.setSigners(wallet.publicKey, ...signers.map((s) => s.publicKey)) if (signers.length > 0) postTransaction.partialSign(...signers); result.push(postTransaction); } return { txIndex: txIndex, transactions: result } } export async function sendAndConfirmTransaction(connection: Connection, serialized: any) { let tries = 0; let signature: any = null; let signatureResponse: any = null; while (true) { connection.sendRawTransaction(serialized, {skipPreflight: true}).catch((e) => { return null; }).then( result => { if (!signature) signature = result; } ); if (signature) { if (tries % 2 == 0) { let response = await connection.getTransaction( signature, { commitment: "confirmed" } ).catch( () => { return "Error"; } ) if (response) { signatureResponse = response; break; } } } tries = tries + 1; if (tries == 30) break; await delay(1000); } return { signature: signature, response: signatureResponse } } export function delay(ms: number) { return new Promise( resolve => setTimeout(resolve, ms) ); } export function createSyncNativeInstruction( nativeAccount: PublicKey ): TransactionInstruction { const dataLayout = struct([ u8("instruction"), ]); const data = Buffer.alloc(dataLayout.span); dataLayout.encode( { instruction: 17, // SyncNative instruction }, data ); const keys = [{ pubkey: nativeAccount, isSigner: false, isWritable: true }]; return new TransactionInstruction({ keys, programId: TOKEN_PROGRAM_ID, data, }); } export async function createAssociatedTokenAccount( account: string | undefined | null, owner: PublicKey, mintAddress: string, connection: Connection, transaction: Transaction, atas: string[] = [] ) { let publicKey if (account) { publicKey = new PublicKey(account) } const mint = new PublicKey(mintAddress) const ata = getAssociatedTokenAddressSync(mint, owner) const infoAta = await connection.getAccountInfo(ata); if ((!publicKey || !ata.equals(publicKey)) && !atas.includes(ata.toBase58()) && !infoAta) { transaction.add( createAssociatedTokenAccountInstruction( owner, ata, owner, mint, ) ) atas.push(ata.toBase58()) } return ata } export async function prepareAccounts( wallet: Wallet, connection: Connection, tokenListData: TokenSettings[], routeData: RouteData, fromTokenAccount: PublicKey|undefined, toTokenAccount: PublicKey|undefined, ): Promise<{ preTransaction: Transaction, postTransaction: Transaction, fromTokenAccount: PublicKey, toTokenAccount: PublicKey, }> { let preTransaction = new Transaction(); let postTransaction = new Transaction(); if (fromTokenAccount == undefined || fromTokenAccount.equals(wallet.publicKey)){ if (tokenListData[routeData.fromTokenId].tokenMint === "So11111111111111111111111111111111111111112") { fromTokenAccount = await createAssociatedTokenAccount(fromTokenAccount?.toBase58(), wallet.publicKey, tokenListData[routeData.fromTokenId].tokenMint, connection, preTransaction); preTransaction.add( SystemProgram.transfer({ fromPubkey: wallet.publicKey, toPubkey: fromTokenAccount, lamports: routeData.fromAmount * 1e9 + 1e7, // 1 sol }) ); preTransaction.add( createSyncNativeInstruction(fromTokenAccount) ); postTransaction.add( createCloseAccountInstruction( fromTokenAccount, wallet.publicKey, wallet.publicKey, ) ) } else fromTokenAccount = await createAssociatedTokenAccount(fromTokenAccount?.toBase58(), wallet.publicKey, tokenListData[routeData.fromTokenId].tokenMint, connection, preTransaction) } if (toTokenAccount == undefined || toTokenAccount.equals(wallet.publicKey)){ if (tokenListData[routeData.toTokenId].tokenMint === "So11111111111111111111111111111111111111112") { toTokenAccount = await createAssociatedTokenAccount(toTokenAccount?.toBase58(), wallet.publicKey, tokenListData[routeData.toTokenId].tokenMint, connection, preTransaction) postTransaction.add( createCloseAccountInstruction( toTokenAccount, wallet.publicKey, wallet.publicKey, ) ) } else toTokenAccount = await createAssociatedTokenAccount(toTokenAccount?.toBase58(), wallet.publicKey, tokenListData[routeData.toTokenId].tokenMint, connection, preTransaction) } return { preTransaction: preTransaction, postTransaction: postTransaction, fromTokenAccount: fromTokenAccount, toTokenAccount: toTokenAccount, }; }