@unloc-xyz/unloc-sdk
Version:
397 lines • 17.5 kB
JavaScript
"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