UNPKG

@unloc-xyz/unloc-sdk

Version:
397 lines 17.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.sleep = exports.getUnixTs = exports.sendSignedTransaction = exports.signTransactions = exports.getVaultOwnerAndNonce = exports.createSerumMarket = exports.createMintPair = exports.checkTxid = exports.getFilteredTokenAccountsByOwner = exports.getMintDecimals = exports.Market = exports.getMarket = exports.getBigNumber = exports.sendTransaction = exports.createAssociatedTokenAccountIfNotExist = exports.getAssociatedPoolKeys = void 0; const web3_js_1 = require("@solana/web3.js"); const spl_token_1 = require("@solana/spl-token"); const anchor = __importStar(require("@project-serum/anchor")); const serum_1 = require("@project-serum/serum"); const raydium_sdk_1 = require("@raydium-io/raydium-sdk"); async function getAssociatedPoolKeys({ programId, serumProgramId, marketId, baseMint, quoteMint, }) { const id = await raydium_sdk_1.Liquidity.getAssociatedId({ programId, marketId }); const lpMint = await raydium_sdk_1.Liquidity.getAssociatedLpMint({ programId, marketId }); const { publicKey: authority, nonce } = await raydium_sdk_1.Liquidity.getAssociatedAuthority({ programId }); const baseVault = await raydium_sdk_1.Liquidity.getAssociatedBaseVault({ programId, marketId }); const quoteVault = await raydium_sdk_1.Liquidity.getAssociatedQuoteVault({ programId, marketId }); const lpVault = await raydium_sdk_1.Liquidity.getAssociatedLpVault({ programId, marketId }); const openOrders = await raydium_sdk_1.Liquidity.getAssociatedOpenOrders({ programId, marketId }); const targetOrders = await raydium_sdk_1.Liquidity.getAssociatedTargetOrders({ programId, marketId }); const withdrawQueue = await raydium_sdk_1.Liquidity.getAssociatedWithdrawQueue({ programId, marketId }); const { publicKey: marketAuthority } = await raydium_sdk_1.Market.getAssociatedAuthority({ programId: serumProgramId, marketId, }); return { // base id, baseMint, quoteMint, lpMint, // version version: 4, programId, // keys authority, nonce, baseVault, quoteVault, lpVault, openOrders, targetOrders, withdrawQueue, // market version marketVersion: 4, marketProgramId: serumProgramId, // market keys marketId, marketAuthority, }; } exports.getAssociatedPoolKeys = getAssociatedPoolKeys; async function createAssociatedTokenAccountIfNotExist(owner, mint, transaction, conn) { const associatedAccount = await raydium_sdk_1.Spl.getAssociatedTokenAccount({ mint, owner }); const payer = owner; const associatedAccountInfo = await conn.getAccountInfo(associatedAccount); if (!associatedAccountInfo) { transaction.add(raydium_sdk_1.Spl.makeCreateAssociatedTokenAccountInstruction({ mint, associatedAccount, owner, payer })); } return associatedAccount; } exports.createAssociatedTokenAccountIfNotExist = createAssociatedTokenAccountIfNotExist; async function sendTransaction(connection, wallet, transaction, signers = []) { const txid = await wallet.sendTransaction(transaction, connection, { signers, skipPreflight: true, preflightCommitment: "confirmed" }); return txid; } exports.sendTransaction = sendTransaction; function getBigNumber(num) { return num === undefined || num === null ? 0 : parseFloat(num.toString()); } exports.getBigNumber = getBigNumber; async function getMarket(conn, marketAddress, serumProgramId) { try { const marketAddressPubKey = new web3_js_1.PublicKey(marketAddress); const market = await Market.load(conn, marketAddressPubKey, undefined, new web3_js_1.PublicKey(serumProgramId)); return market; } catch (error) { console.log("get market err: ", error); throw error; } } exports.getMarket = getMarket; class Market extends serum_1.Market { constructor() { super(...arguments); this.baseVault = null; this.quoteVault = null; this.requestQueue = null; this.eventQueue = null; this.bids = null; this.asks = null; this.baseLotSize = 0; this.quoteLotSize = 0; // private _decoded: any this.quoteMint = null; this.baseMint = null; this.vaultSignerNonce = null; } static async load(connection, address, options = {}, programId) { const { owner, data } = throwIfNull(await connection.getAccountInfo(address), 'Market not found'); if (!owner.equals(programId)) { throw new Error('Address not owned by program: ' + owner.toBase58()); } const decoded = this.getLayout(programId).decode(data); if (!decoded.accountFlags.initialized || !decoded.accountFlags.market || !decoded.ownAddress.equals(address)) { throw new Error('Invalid market'); } const [baseMintDecimals, quoteMintDecimals] = await Promise.all([ getMintDecimals(connection, decoded.baseMint), getMintDecimals(connection, decoded.quoteMint) ]); const market = new Market(decoded, baseMintDecimals, quoteMintDecimals, options, programId); // market._decoded = decoded market.baseLotSize = decoded.baseLotSize; market.quoteLotSize = decoded.quoteLotSize; market.baseVault = decoded.baseVault; market.quoteVault = decoded.quoteVault; market.requestQueue = decoded.requestQueue; market.eventQueue = decoded.eventQueue; market.bids = decoded.bids; market.asks = decoded.asks; market.quoteMint = decoded.quoteMint; market.baseMint = decoded.baseMint; market.vaultSignerNonce = decoded.vaultSignerNonce; return market; } } exports.Market = Market; async function getMintDecimals(connection, mint) { const { data } = throwIfNull(await connection.getAccountInfo(mint), 'mint not found'); const { decimals } = raydium_sdk_1.SPL_MINT_LAYOUT.decode(data); return decimals; } exports.getMintDecimals = getMintDecimals; function throwIfNull(value, message = 'account not found') { if (value === null) { throw new Error(message); } return value; } async function getFilteredTokenAccountsByOwner(connection, programId, mint) { // @ts-ignore const resp = await connection._rpcRequest('getTokenAccountsByOwner', [ programId.toBase58(), { mint: mint.toBase58() }, { encoding: 'jsonParsed' } ]); if (resp.error) { throw new Error(resp.error.message); } return resp.result; } exports.getFilteredTokenAccountsByOwner = getFilteredTokenAccountsByOwner; async function checkTxid(conn, txid) { let txidSuccessFlag = 0; await conn.onSignature(txid, function (_signatureResult, _context) { if (_signatureResult.err) { txidSuccessFlag = -1; } else { txidSuccessFlag = 1; } }); const timeAwait = new Date().getTime(); let outOfWhile = false; while (!outOfWhile) { console.log('wait txid:', txid, outOfWhile, txidSuccessFlag, (new Date().getTime() - timeAwait) / 1000); if (txidSuccessFlag !== 0) { outOfWhile = true; } await new Promise((resolve) => setTimeout(resolve, 1000)); } if (txidSuccessFlag !== 1) { throw new Error('Transaction failed'); } } exports.checkTxid = checkTxid; async function createMintPair(provider) { const connection = provider.connection; const wallet = provider.wallet; const tokenA = await spl_token_1.Token.createMint(connection, wallet.payer, wallet.publicKey, null, 9, spl_token_1.TOKEN_PROGRAM_ID); const tokenB = await spl_token_1.Token.createMint(connection, wallet.payer, wallet.publicKey, null, 9, spl_token_1.TOKEN_PROGRAM_ID); const tokenAMintAddress = tokenA.publicKey; const tokenBMintAddress = tokenB.publicKey; const associatedTokenA = await spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, tokenAMintAddress, wallet.publicKey, true); const associatedTokenB = await spl_token_1.Token.getAssociatedTokenAddress(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, tokenBMintAddress, wallet.publicKey, true); const tx1 = new web3_js_1.Transaction(); tx1.add(spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, tokenAMintAddress, associatedTokenA, wallet.publicKey, wallet.publicKey), spl_token_1.Token.createAssociatedTokenAccountInstruction(spl_token_1.ASSOCIATED_TOKEN_PROGRAM_ID, spl_token_1.TOKEN_PROGRAM_ID, tokenBMintAddress, associatedTokenB, wallet.publicKey, wallet.publicKey)); let txid = await provider.sendAndConfirm(tx1); sleep(5000); const tx2 = new web3_js_1.Transaction(); tx2.add(spl_token_1.Token.createMintToInstruction(spl_token_1.TOKEN_PROGRAM_ID, tokenAMintAddress, associatedTokenA, wallet.publicKey, [wallet.payer], 100000000000000), spl_token_1.Token.createMintToInstruction(spl_token_1.TOKEN_PROGRAM_ID, tokenBMintAddress, associatedTokenB, wallet.publicKey, [wallet.payer], 200000000000000)); txid = await provider.sendAndConfirm(tx2); console.log("create tokenA: ", tokenA.publicKey.toString(), " tokenB: ", tokenBMintAddress.toString(), "mint txid: ", txid); sleep(5000); return { tokenAMintAddress, tokenBMintAddress }; } exports.createMintPair = createMintPair; async function createSerumMarket({ connection, wallet, baseMint, quoteMint, baseLotSize, quoteLotSize, dexProgram, market }) { const requestQueue = new web3_js_1.Keypair(); const eventQueue = new web3_js_1.Keypair(); const bids = new web3_js_1.Keypair(); const asks = new web3_js_1.Keypair(); const baseVault = new web3_js_1.Keypair(); const quoteVault = new web3_js_1.Keypair(); const feeRateBps = 0; const quoteDustThreshold = new anchor.BN(10); const { vaultOwner, vaultNonce } = await getVaultOwnerAndNonce(market.publicKey, dexProgram); const tx1 = new web3_js_1.Transaction(); tx1.add(web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: baseVault.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(165), space: 165, programId: serum_1.TokenInstructions.TOKEN_PROGRAM_ID, }), web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: quoteVault.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(165), space: 165, programId: serum_1.TokenInstructions.TOKEN_PROGRAM_ID, }), serum_1.TokenInstructions.initializeAccount({ account: baseVault.publicKey, mint: baseMint, owner: vaultOwner, }), serum_1.TokenInstructions.initializeAccount({ account: quoteVault.publicKey, mint: quoteMint, owner: vaultOwner, })); const tx2 = new web3_js_1.Transaction(); tx2.add(web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: market.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(Market.getLayout(dexProgram).span), space: Market.getLayout(dexProgram).span, programId: dexProgram, }), web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: requestQueue.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(5120 + 12), space: 5120 + 12, programId: dexProgram, }), web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: eventQueue.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(262144 + 12), space: 262144 + 12, programId: dexProgram, }), web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: bids.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(65536 + 12), space: 65536 + 12, programId: dexProgram, }), web3_js_1.SystemProgram.createAccount({ fromPubkey: wallet.publicKey, newAccountPubkey: asks.publicKey, lamports: await connection.getMinimumBalanceForRentExemption(65536 + 12), space: 65536 + 12, programId: dexProgram, }), serum_1.DexInstructions.initializeMarket({ market: market.publicKey, requestQueue: requestQueue.publicKey, eventQueue: eventQueue.publicKey, bids: bids.publicKey, asks: asks.publicKey, baseVault: baseVault.publicKey, quoteVault: quoteVault.publicKey, baseMint, quoteMint, baseLotSize: new anchor.BN(baseLotSize), quoteLotSize: new anchor.BN(quoteLotSize), feeRateBps, vaultSignerNonce: vaultNonce, quoteDustThreshold, programId: dexProgram, authority: undefined, })); const signedTransactions = await signTransactions({ transactionsAndSigners: [ { transaction: tx1, signers: [baseVault, quoteVault] }, { transaction: tx2, signers: [market, requestQueue, eventQueue, bids, asks], }, ], wallet: wallet, connection: connection, }); for (let signedTransaction of signedTransactions) { await sendSignedTransaction({ signedTransaction, connection: connection, }); } return { market: market.publicKey, requestQueue: requestQueue.publicKey, eventQueue: eventQueue.publicKey, bids: bids.publicKey, asks: asks.publicKey, baseVault: baseVault.publicKey, quoteVault: quoteVault.publicKey, baseMint, quoteMint, baseLotSize: new anchor.BN(baseLotSize), quoteLotSize: new anchor.BN(quoteLotSize), feeRateBps, vaultOwner, vaultSignerNonce: vaultNonce, quoteDustThreshold, programId: dexProgram, // authority: undefined, }; } exports.createSerumMarket = createSerumMarket; async function getVaultOwnerAndNonce(marketId, dexProgramId) { const vaultNonce = new anchor.BN(0); while (true) { try { const vaultOwner = await web3_js_1.PublicKey.createProgramAddress([marketId.toBuffer(), vaultNonce.toArrayLike(Buffer, 'le', 8)], dexProgramId); return { vaultOwner, vaultNonce }; } catch (e) { vaultNonce.iaddn(1); } } } exports.getVaultOwnerAndNonce = getVaultOwnerAndNonce; async function signTransactions({ transactionsAndSigners, wallet, connection, }) { const blockhash = (await connection.getRecentBlockhash('max')).blockhash; transactionsAndSigners.forEach(({ transaction, signers = [] }) => { transaction.recentBlockhash = blockhash; transaction.setSigners(wallet.publicKey, ...signers.map((s) => s.publicKey)); if ((signers === null || signers === void 0 ? void 0 : signers.length) > 0) { transaction.partialSign(...signers); } }); return await wallet.signAllTransactions(transactionsAndSigners.map(({ transaction }) => transaction)); } exports.signTransactions = signTransactions; async function sendSignedTransaction({ signedTransaction, connection, timeout = 15000, }) { const rawTransaction = signedTransaction.serialize(); const startTime = (0, exports.getUnixTs)(); const txid = await connection.sendRawTransaction(rawTransaction, { skipPreflight: true, }); console.log('Started awaiting confirmation for', txid); await sleep(timeout); console.log('Latency', txid, (0, exports.getUnixTs)() - startTime); return txid; } exports.sendSignedTransaction = sendSignedTransaction; const getUnixTs = () => { return new Date().getTime() / 1000; }; exports.getUnixTs = getUnixTs; async function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } exports.sleep = sleep; //# sourceMappingURL=buyback-utils.js.map