UNPKG

@frakters/nft-lending-v2

Version:

Client library for interacting with nft lenging solana program

879 lines (878 loc) 46.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.requestInfos = exports.getLiquidityInfo = exports.getLiquidityInfoSimilar = exports.getLpMintListDecimals = exports.getLpMintInfo = exports.AMM_INFO_LAYOUT_STABLE = exports.AMM_INFO_LAYOUT_V4 = exports.AMM_INFO_LAYOUT_V3 = exports.AMM_INFO_LAYOUT = exports.removeLiquidityInstructionV4 = exports.removeLiquidityInstruction = exports.addLiquidityInstructionV4 = exports.addLiquidityInstruction = exports.removeLiquidity = exports.addLiquidity = exports.getOutAmountStable = exports.getOutAmount = exports.getPrice = exports.getPoolByTokenMintAddresses = exports.getPoolByLpMintAddress = exports.getLpMintByTokenMintAddresses = void 0; const bignumber_js_1 = __importDefault(require("bignumber.js")); // @ts-ignore const buffer_layout_1 = require("buffer-layout"); const borsh_1 = require("@project-serum/borsh"); const token_instructions_1 = require("@project-serum/serum/lib/token-instructions"); const web3_js_1 = require("@solana/web3.js"); const ids_1 = require("./ids"); const pools_1 = require("./pools"); Object.defineProperty(exports, "getLpMintByTokenMintAddresses", { enumerable: true, get: function () { return pools_1.getLpMintByTokenMintAddresses; } }); Object.defineProperty(exports, "getPoolByLpMintAddress", { enumerable: true, get: function () { return pools_1.getPoolByLpMintAddress; } }); Object.defineProperty(exports, "getPoolByTokenMintAddresses", { enumerable: true, get: function () { return pools_1.getPoolByTokenMintAddresses; } }); const safe_math_1 = require("./safe-math"); const tokens_1 = require("./tokens"); const web3_1 = require("./web3"); const layouts_1 = require("./layouts"); const serum_1 = require("@project-serum/serum"); const lodash_1 = require("lodash"); function getPrice(poolInfo, coinBase = true) { const { coin, pc } = poolInfo; if (!coin.balance || !pc.balance) { return new bignumber_js_1.default(0); } if (poolInfo.version === 5) { const { currentK = 1 } = poolInfo; const systemDecimal = Math.max(coin.decimals, pc.decimals); const k = currentK / (Math.pow(10, systemDecimal) * Math.pow(10, systemDecimal)); const y = parseFloat(coin.balance.fixed()); let price = Math.sqrt(((10 - 1) * y * y) / (10 * y * y - k)); if (!coinBase) price = 1 / price; return new bignumber_js_1.default(price); } else if (coinBase) { return pc.balance.toEther().dividedBy(coin.balance.toEther()); } else { return coin.balance.toEther().dividedBy(pc.balance.toEther()); } } exports.getPrice = getPrice; function getOutAmount(poolInfo, amount, fromCoinMint, toCoinMint, slippage) { const { coin, pc } = poolInfo; const price = getPrice(poolInfo); const fromAmount = new bignumber_js_1.default(amount); let outAmount = new bignumber_js_1.default(0); const percent = new bignumber_js_1.default(100).plus(slippage).dividedBy(100); if (!coin.balance || !pc.balance) { return outAmount; } if (fromCoinMint === coin.mintAddress && toCoinMint === pc.mintAddress) { // outcoin is pc outAmount = fromAmount.multipliedBy(price); outAmount = outAmount.multipliedBy(percent); } else if (fromCoinMint === pc.mintAddress && toCoinMint === coin.mintAddress) { // outcoin is coin outAmount = fromAmount.dividedBy(price); outAmount = outAmount.multipliedBy(percent); } return outAmount; } exports.getOutAmount = getOutAmount; function getOutAmountStable(poolInfo, amount, fromCoinMint, toCoinMint, slippage) { const { coin, pc, currentK } = poolInfo; const systemDecimal = Math.max(coin.decimals, pc.decimals); const k = currentK / (Math.pow(10, systemDecimal) * Math.pow(10, systemDecimal)); const y = parseFloat(coin.balance.fixed()); const price = Math.sqrt(((10 - 1) * y * y) / (10 * y * y - k)); const amountIn = parseFloat(amount); let amountOut = 1; if (fromCoinMint === coin.mintAddress && toCoinMint === pc.mintAddress) { // outcoin is pc amountOut = amountIn * price; } else if (fromCoinMint === pc.mintAddress && toCoinMint === coin.mintAddress) { // outcoin is coin amountOut = amountIn / price; } const amountOutWithSlippage = amountOut / (1 - slippage / 100); // const price = Math.sqrt((10 - 1) * y * y /(10 * y * y - k)) // const afterY = y - amountOut // const afterPrice = Math.sqrt((10 - 1) * afterY * afterY /(10 * afterY * afterY - k)) // const priceImpact = (beforePrice - afterPrice) / beforePrice * 100 return new bignumber_js_1.default(amountOutWithSlippage); } exports.getOutAmountStable = getOutAmountStable; /* eslint-disable */ function addLiquidity(connection, wallet, poolInfo, fromCoinAccount, toCoinAccount, lpAccount, fromCoin, toCoin, fromAmount, toAmount, fixedCoin) { return __awaiter(this, void 0, void 0, function* () { if (!connection || !wallet) throw new Error('Miss connection'); if (!poolInfo || !fromCoin || !toCoin) { throw new Error('Miss pool infomations'); } if (!fromCoinAccount || !toCoinAccount) { throw new Error('Miss account infomations'); } if (!fromAmount || !toAmount) { throw new Error('Miss amount infomations'); } const transaction = new web3_js_1.Transaction(); const signers = []; const owner = wallet.publicKey; const userAccounts = [new web3_js_1.PublicKey(fromCoinAccount), new web3_js_1.PublicKey(toCoinAccount)]; const userAmounts = [fromAmount, toAmount]; if (poolInfo.coin.mintAddress === toCoin.mintAddress && poolInfo.pc.mintAddress === fromCoin.mintAddress) { userAccounts.reverse(); userAmounts.reverse(); } const userCoinTokenAccount = userAccounts[0]; const userPcTokenAccount = userAccounts[1]; const coinAmount = layouts_1.getBigNumber(new safe_math_1.TokenAmount(userAmounts[0], poolInfo.coin.decimals, false).wei); const pcAmount = layouts_1.getBigNumber(new safe_math_1.TokenAmount(userAmounts[1], poolInfo.pc.decimals, false).wei); let wrappedCoinSolAccount; if (poolInfo.coin.mintAddress === tokens_1.NATIVE_SOL.mintAddress) { wrappedCoinSolAccount = yield web3_1.createTokenAccountIfNotExist(connection, wrappedCoinSolAccount, owner, tokens_1.TOKENS.WSOL.mintAddress, coinAmount + 1e7, transaction, signers); } let wrappedSolAccount; if (poolInfo.pc.mintAddress === tokens_1.NATIVE_SOL.mintAddress) { wrappedSolAccount = yield web3_1.createTokenAccountIfNotExist(connection, wrappedSolAccount, owner, tokens_1.TOKENS.WSOL.mintAddress, pcAmount + 1e7, transaction, signers); } let userLpTokenAccount = yield web3_1.createAssociatedTokenAccountIfNotExist(lpAccount, owner, poolInfo.lp.mintAddress, transaction); transaction.add([4, 5].includes(poolInfo.version) ? addLiquidityInstructionV4(new web3_js_1.PublicKey(poolInfo.programId), new web3_js_1.PublicKey(poolInfo.ammId), new web3_js_1.PublicKey(poolInfo.ammAuthority), new web3_js_1.PublicKey(poolInfo.ammOpenOrders), new web3_js_1.PublicKey(poolInfo.ammTargetOrders), new web3_js_1.PublicKey(poolInfo.lp.mintAddress), new web3_js_1.PublicKey(poolInfo.poolCoinTokenAccount), new web3_js_1.PublicKey(poolInfo.poolPcTokenAccount), new web3_js_1.PublicKey(poolInfo.serumMarket), wrappedCoinSolAccount ? wrappedCoinSolAccount : userCoinTokenAccount, wrappedSolAccount ? wrappedSolAccount : userPcTokenAccount, userLpTokenAccount, owner, coinAmount, pcAmount, fixedCoin === poolInfo.coin.mintAddress ? 0 : 1) : addLiquidityInstruction(new web3_js_1.PublicKey(poolInfo.programId), new web3_js_1.PublicKey(poolInfo.ammId), new web3_js_1.PublicKey(poolInfo.ammAuthority), new web3_js_1.PublicKey(poolInfo.ammOpenOrders), new web3_js_1.PublicKey(poolInfo.ammQuantities), new web3_js_1.PublicKey(poolInfo.lp.mintAddress), new web3_js_1.PublicKey(poolInfo.poolCoinTokenAccount), new web3_js_1.PublicKey(poolInfo.poolPcTokenAccount), new web3_js_1.PublicKey(poolInfo.serumMarket), wrappedCoinSolAccount ? wrappedCoinSolAccount : userCoinTokenAccount, wrappedSolAccount ? wrappedSolAccount : userPcTokenAccount, userLpTokenAccount, owner, coinAmount, pcAmount, fixedCoin === poolInfo.coin.mintAddress ? 0 : 1)); if (wrappedCoinSolAccount) { transaction.add(token_instructions_1.closeAccount({ source: wrappedCoinSolAccount, destination: owner, owner: owner, })); } if (wrappedSolAccount) { transaction.add(token_instructions_1.closeAccount({ source: wrappedSolAccount, destination: owner, owner: owner, })); } return yield web3_1.sendTransaction(connection, wallet, transaction, signers); }); } exports.addLiquidity = addLiquidity; function removeLiquidity(connection, wallet, poolInfo, lpAccount, fromCoinAccount, toCoinAccount, amount) { return __awaiter(this, void 0, void 0, function* () { if (!connection || !wallet) throw new Error('Miss connection'); if (!poolInfo) throw new Error('Miss pool infomations'); if (!lpAccount) throw new Error('Miss account infomations'); if (!amount) throw new Error('Miss amount infomations'); const transaction = new web3_js_1.Transaction(); const signers = []; const owner = wallet.publicKey; const lpAmount = layouts_1.getBigNumber(new safe_math_1.TokenAmount(amount, poolInfo.lp.decimals, false).wei); let needCloseFromTokenAccount = false; let newFromTokenAccount; if (poolInfo.coin.mintAddress === tokens_1.NATIVE_SOL.mintAddress) { newFromTokenAccount = yield web3_1.createTokenAccountIfNotExist(connection, newFromTokenAccount, owner, tokens_1.TOKENS.WSOL.mintAddress, null, transaction, signers); needCloseFromTokenAccount = true; } else { newFromTokenAccount = yield web3_1.createAssociatedTokenAccountIfNotExist(fromCoinAccount, owner, poolInfo.coin.mintAddress, transaction); } let needCloseToTokenAccount = false; let newToTokenAccount; if (poolInfo.pc.mintAddress === tokens_1.NATIVE_SOL.mintAddress) { newToTokenAccount = yield web3_1.createTokenAccountIfNotExist(connection, newToTokenAccount, owner, tokens_1.TOKENS.WSOL.mintAddress, null, transaction, signers); needCloseToTokenAccount = true; } else { newToTokenAccount = yield web3_1.createAssociatedTokenAccountIfNotExist(toCoinAccount, owner, poolInfo.pc.mintAddress === tokens_1.NATIVE_SOL.mintAddress ? tokens_1.TOKENS.WSOL.mintAddress : poolInfo.pc.mintAddress, transaction); } transaction.add([4, 5].includes(poolInfo.version) ? removeLiquidityInstructionV4(new web3_js_1.PublicKey(poolInfo.programId), new web3_js_1.PublicKey(poolInfo.ammId), new web3_js_1.PublicKey(poolInfo.ammAuthority), new web3_js_1.PublicKey(poolInfo.ammOpenOrders), new web3_js_1.PublicKey(poolInfo.ammTargetOrders), new web3_js_1.PublicKey(poolInfo.lp.mintAddress), new web3_js_1.PublicKey(poolInfo.poolCoinTokenAccount), new web3_js_1.PublicKey(poolInfo.poolPcTokenAccount), new web3_js_1.PublicKey(poolInfo.poolWithdrawQueue), new web3_js_1.PublicKey(poolInfo.poolTempLpTokenAccount), new web3_js_1.PublicKey(poolInfo.serumProgramId), new web3_js_1.PublicKey(poolInfo.serumMarket), new web3_js_1.PublicKey(poolInfo.serumCoinVaultAccount), new web3_js_1.PublicKey(poolInfo.serumPcVaultAccount), new web3_js_1.PublicKey(poolInfo.serumVaultSigner), new web3_js_1.PublicKey(lpAccount), newFromTokenAccount, newToTokenAccount, owner, lpAmount) : removeLiquidityInstruction(new web3_js_1.PublicKey(poolInfo.programId), new web3_js_1.PublicKey(poolInfo.ammId), new web3_js_1.PublicKey(poolInfo.ammAuthority), new web3_js_1.PublicKey(poolInfo.ammOpenOrders), new web3_js_1.PublicKey(poolInfo.ammQuantities), new web3_js_1.PublicKey(poolInfo.lp.mintAddress), new web3_js_1.PublicKey(poolInfo.poolCoinTokenAccount), new web3_js_1.PublicKey(poolInfo.poolPcTokenAccount), new web3_js_1.PublicKey(poolInfo.poolWithdrawQueue), new web3_js_1.PublicKey(poolInfo.poolTempLpTokenAccount), new web3_js_1.PublicKey(poolInfo.serumProgramId), new web3_js_1.PublicKey(poolInfo.serumMarket), new web3_js_1.PublicKey(poolInfo.serumCoinVaultAccount), new web3_js_1.PublicKey(poolInfo.serumPcVaultAccount), new web3_js_1.PublicKey(poolInfo.serumVaultSigner), new web3_js_1.PublicKey(lpAccount), newFromTokenAccount, newToTokenAccount, owner, lpAmount)); if (needCloseFromTokenAccount) { transaction.add(token_instructions_1.closeAccount({ source: newFromTokenAccount, destination: owner, owner: owner, })); } if (needCloseToTokenAccount) { transaction.add(token_instructions_1.closeAccount({ source: newToTokenAccount, destination: owner, owner: owner, })); } return yield web3_1.sendTransaction(connection, wallet, transaction, signers); }); } exports.removeLiquidity = removeLiquidity; function addLiquidityInstruction(programId, // tokenProgramId: PublicKey, // amm ammId, ammAuthority, ammOpenOrders, ammQuantities, lpMintAddress, poolCoinTokenAccount, poolPcTokenAccount, // serum serumMarket, // user userCoinTokenAccount, userPcTokenAccount, userLpTokenAccount, userOwner, maxCoinAmount, maxPcAmount, fixedFromCoin) { const dataLayout = buffer_layout_1.struct([buffer_layout_1.u8('instruction'), buffer_layout_1.nu64('maxCoinAmount'), buffer_layout_1.nu64('maxPcAmount'), buffer_layout_1.nu64('fixedFromCoin')]); const keys = [ { pubkey: ids_1.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ammId, isSigner: false, isWritable: true }, { pubkey: ammAuthority, isSigner: false, isWritable: false }, { pubkey: ammOpenOrders, isSigner: false, isWritable: false }, { pubkey: ammQuantities, isSigner: false, isWritable: true }, { pubkey: lpMintAddress, isSigner: false, isWritable: true }, { pubkey: poolCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: serumMarket, isSigner: false, isWritable: false }, { pubkey: userCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: userPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: userLpTokenAccount, isSigner: false, isWritable: true }, { pubkey: userOwner, isSigner: true, isWritable: false }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ instruction: 3, maxCoinAmount, maxPcAmount, fixedFromCoin, }, data); return new web3_js_1.TransactionInstruction({ keys, programId, data, }); } exports.addLiquidityInstruction = addLiquidityInstruction; function addLiquidityInstructionV4(programId, // tokenProgramId: PublicKey, // amm ammId, ammAuthority, ammOpenOrders, ammTargetOrders, lpMintAddress, poolCoinTokenAccount, poolPcTokenAccount, // serum serumMarket, // user userCoinTokenAccount, userPcTokenAccount, userLpTokenAccount, userOwner, maxCoinAmount, maxPcAmount, fixedFromCoin) { const dataLayout = buffer_layout_1.struct([buffer_layout_1.u8('instruction'), buffer_layout_1.nu64('maxCoinAmount'), buffer_layout_1.nu64('maxPcAmount'), buffer_layout_1.nu64('fixedFromCoin')]); const keys = [ { pubkey: ids_1.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ammId, isSigner: false, isWritable: true }, { pubkey: ammAuthority, isSigner: false, isWritable: false }, { pubkey: ammOpenOrders, isSigner: false, isWritable: false }, { pubkey: ammTargetOrders, isSigner: false, isWritable: true }, { pubkey: lpMintAddress, isSigner: false, isWritable: true }, { pubkey: poolCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: serumMarket, isSigner: false, isWritable: false }, { pubkey: userCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: userPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: userLpTokenAccount, isSigner: false, isWritable: true }, { pubkey: userOwner, isSigner: true, isWritable: false }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ instruction: 3, maxCoinAmount, maxPcAmount, fixedFromCoin, }, data); return new web3_js_1.TransactionInstruction({ keys, programId, data, }); } exports.addLiquidityInstructionV4 = addLiquidityInstructionV4; function removeLiquidityInstruction(programId, // tokenProgramId: PublicKey, // amm ammId, ammAuthority, ammOpenOrders, ammQuantities, lpMintAddress, poolCoinTokenAccount, poolPcTokenAccount, poolWithdrawQueue, poolTempLpTokenAccount, // serum serumProgramId, serumMarket, serumCoinVaultAccount, serumPcVaultAccount, serumVaultSigner, // user userLpTokenAccount, userCoinTokenAccount, userPcTokenAccount, userOwner, amount) { const dataLayout = buffer_layout_1.struct([buffer_layout_1.u8('instruction'), buffer_layout_1.nu64('amount')]); const keys = [ { pubkey: ids_1.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ammId, isSigner: false, isWritable: true }, { pubkey: ammAuthority, isSigner: false, isWritable: false }, { pubkey: ammOpenOrders, isSigner: false, isWritable: true }, { pubkey: ammQuantities, isSigner: false, isWritable: true }, { pubkey: lpMintAddress, isSigner: false, isWritable: true }, { pubkey: poolCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolWithdrawQueue, isSigner: false, isWritable: true }, { pubkey: poolTempLpTokenAccount, isSigner: false, isWritable: true }, { pubkey: serumProgramId, isSigner: false, isWritable: false }, { pubkey: serumMarket, isSigner: false, isWritable: true }, { pubkey: serumCoinVaultAccount, isSigner: false, isWritable: true }, { pubkey: serumPcVaultAccount, isSigner: false, isWritable: true }, { pubkey: serumVaultSigner, isSigner: false, isWritable: false }, { pubkey: userLpTokenAccount, isSigner: false, isWritable: true }, { pubkey: userCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: userPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: userOwner, isSigner: true, isWritable: false }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ instruction: 4, amount: amount, }, data); return new web3_js_1.TransactionInstruction({ keys, programId, data, }); } exports.removeLiquidityInstruction = removeLiquidityInstruction; function removeLiquidityInstructionV4(programId, // tokenProgramId: PublicKey, // amm ammId, ammAuthority, ammOpenOrders, ammTargetOrders, lpMintAddress, poolCoinTokenAccount, poolPcTokenAccount, poolWithdrawQueue, poolTempLpTokenAccount, // serum serumProgramId, serumMarket, serumCoinVaultAccount, serumPcVaultAccount, serumVaultSigner, // user userLpTokenAccount, userCoinTokenAccount, userPcTokenAccount, userOwner, amount) { const dataLayout = buffer_layout_1.struct([buffer_layout_1.u8('instruction'), buffer_layout_1.nu64('amount')]); const keys = [ { pubkey: ids_1.TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: ammId, isSigner: false, isWritable: true }, { pubkey: ammAuthority, isSigner: false, isWritable: false }, { pubkey: ammOpenOrders, isSigner: false, isWritable: true }, { pubkey: ammTargetOrders, isSigner: false, isWritable: true }, { pubkey: lpMintAddress, isSigner: false, isWritable: true }, { pubkey: poolCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: poolWithdrawQueue, isSigner: false, isWritable: true }, { pubkey: poolTempLpTokenAccount, isSigner: false, isWritable: true }, { pubkey: serumProgramId, isSigner: false, isWritable: false }, { pubkey: serumMarket, isSigner: false, isWritable: true }, { pubkey: serumCoinVaultAccount, isSigner: false, isWritable: true }, { pubkey: serumPcVaultAccount, isSigner: false, isWritable: true }, { pubkey: serumVaultSigner, isSigner: false, isWritable: false }, { pubkey: userLpTokenAccount, isSigner: false, isWritable: true }, { pubkey: userCoinTokenAccount, isSigner: false, isWritable: true }, { pubkey: userPcTokenAccount, isSigner: false, isWritable: true }, { pubkey: userOwner, isSigner: true, isWritable: false }, ]; const data = Buffer.alloc(dataLayout.span); dataLayout.encode({ instruction: 4, amount: amount, }, data); return new web3_js_1.TransactionInstruction({ keys, programId, data, }); } exports.removeLiquidityInstructionV4 = removeLiquidityInstructionV4; exports.AMM_INFO_LAYOUT = buffer_layout_1.struct([ borsh_1.u64('status'), borsh_1.u64('nonce'), borsh_1.u64('orderNum'), borsh_1.u64('depth'), borsh_1.u64('coinDecimals'), borsh_1.u64('pcDecimals'), borsh_1.u64('state'), borsh_1.u64('resetFlag'), borsh_1.u64('fee'), borsh_1.u64('minSize'), borsh_1.u64('volMaxCutRatio'), borsh_1.u64('pnlRatio'), borsh_1.u64('amountWaveRatio'), borsh_1.u64('coinLotSize'), borsh_1.u64('pcLotSize'), borsh_1.u64('minPriceMultiplier'), borsh_1.u64('maxPriceMultiplier'), borsh_1.u64('needTakePnlCoin'), borsh_1.u64('needTakePnlPc'), borsh_1.u64('totalPnlX'), borsh_1.u64('totalPnlY'), borsh_1.u64('systemDecimalsValue'), borsh_1.publicKey('poolCoinTokenAccount'), borsh_1.publicKey('poolPcTokenAccount'), borsh_1.publicKey('coinMintAddress'), borsh_1.publicKey('pcMintAddress'), borsh_1.publicKey('lpMintAddress'), borsh_1.publicKey('ammOpenOrders'), borsh_1.publicKey('serumMarket'), borsh_1.publicKey('serumProgramId'), borsh_1.publicKey('ammTargetOrders'), borsh_1.publicKey('ammQuantities'), borsh_1.publicKey('poolWithdrawQueue'), borsh_1.publicKey('poolTempLpTokenAccount'), borsh_1.publicKey('ammOwner'), borsh_1.publicKey('pnlOwner'), ]); exports.AMM_INFO_LAYOUT_V3 = buffer_layout_1.struct([ borsh_1.u64('status'), borsh_1.u64('nonce'), borsh_1.u64('orderNum'), borsh_1.u64('depth'), borsh_1.u64('coinDecimals'), borsh_1.u64('pcDecimals'), borsh_1.u64('state'), borsh_1.u64('resetFlag'), borsh_1.u64('fee'), borsh_1.u64('min_separate'), borsh_1.u64('minSize'), borsh_1.u64('volMaxCutRatio'), borsh_1.u64('pnlRatio'), borsh_1.u64('amountWaveRatio'), borsh_1.u64('coinLotSize'), borsh_1.u64('pcLotSize'), borsh_1.u64('minPriceMultiplier'), borsh_1.u64('maxPriceMultiplier'), borsh_1.u64('needTakePnlCoin'), borsh_1.u64('needTakePnlPc'), borsh_1.u64('totalPnlX'), borsh_1.u64('totalPnlY'), borsh_1.u64('poolTotalDepositPc'), borsh_1.u64('poolTotalDepositCoin'), borsh_1.u64('systemDecimalsValue'), borsh_1.publicKey('poolCoinTokenAccount'), borsh_1.publicKey('poolPcTokenAccount'), borsh_1.publicKey('coinMintAddress'), borsh_1.publicKey('pcMintAddress'), borsh_1.publicKey('lpMintAddress'), borsh_1.publicKey('ammOpenOrders'), borsh_1.publicKey('serumMarket'), borsh_1.publicKey('serumProgramId'), borsh_1.publicKey('ammTargetOrders'), borsh_1.publicKey('ammQuantities'), borsh_1.publicKey('poolWithdrawQueue'), borsh_1.publicKey('poolTempLpTokenAccount'), borsh_1.publicKey('ammOwner'), borsh_1.publicKey('pnlOwner'), borsh_1.publicKey('srmTokenAccount'), ]); exports.AMM_INFO_LAYOUT_V4 = buffer_layout_1.struct([ borsh_1.u64('status'), borsh_1.u64('nonce'), borsh_1.u64('orderNum'), borsh_1.u64('depth'), borsh_1.u64('coinDecimals'), borsh_1.u64('pcDecimals'), borsh_1.u64('state'), borsh_1.u64('resetFlag'), borsh_1.u64('minSize'), borsh_1.u64('volMaxCutRatio'), borsh_1.u64('amountWaveRatio'), borsh_1.u64('coinLotSize'), borsh_1.u64('pcLotSize'), borsh_1.u64('minPriceMultiplier'), borsh_1.u64('maxPriceMultiplier'), borsh_1.u64('systemDecimalsValue'), // Fees borsh_1.u64('minSeparateNumerator'), borsh_1.u64('minSeparateDenominator'), borsh_1.u64('tradeFeeNumerator'), borsh_1.u64('tradeFeeDenominator'), borsh_1.u64('pnlNumerator'), borsh_1.u64('pnlDenominator'), borsh_1.u64('swapFeeNumerator'), borsh_1.u64('swapFeeDenominator'), // OutPutData borsh_1.u64('needTakePnlCoin'), borsh_1.u64('needTakePnlPc'), borsh_1.u64('totalPnlPc'), borsh_1.u64('totalPnlCoin'), borsh_1.u128('poolTotalDepositPc'), borsh_1.u128('poolTotalDepositCoin'), borsh_1.u128('swapCoinInAmount'), borsh_1.u128('swapPcOutAmount'), borsh_1.u64('swapCoin2PcFee'), borsh_1.u128('swapPcInAmount'), borsh_1.u128('swapCoinOutAmount'), borsh_1.u64('swapPc2CoinFee'), borsh_1.publicKey('poolCoinTokenAccount'), borsh_1.publicKey('poolPcTokenAccount'), borsh_1.publicKey('coinMintAddress'), borsh_1.publicKey('pcMintAddress'), borsh_1.publicKey('lpMintAddress'), borsh_1.publicKey('ammOpenOrders'), borsh_1.publicKey('serumMarket'), borsh_1.publicKey('serumProgramId'), borsh_1.publicKey('ammTargetOrders'), borsh_1.publicKey('poolWithdrawQueue'), borsh_1.publicKey('poolTempLpTokenAccount'), borsh_1.publicKey('ammOwner'), borsh_1.publicKey('pnlOwner'), ]); exports.AMM_INFO_LAYOUT_STABLE = buffer_layout_1.struct([ borsh_1.u64('status'), borsh_1.publicKey('own_address'), borsh_1.u64('nonce'), borsh_1.u64('orderNum'), borsh_1.u64('depth'), borsh_1.u64('coinDecimals'), borsh_1.u64('pcDecimals'), borsh_1.u64('state'), borsh_1.u64('resetFlag'), borsh_1.u64('minSize'), borsh_1.u64('volMaxCutRatio'), borsh_1.u64('amountWaveRatio'), borsh_1.u64('coinLotSize'), borsh_1.u64('pcLotSize'), borsh_1.u64('minPriceMultiplier'), borsh_1.u64('maxPriceMultiplier'), borsh_1.u64('systemDecimalsValue'), borsh_1.u64('ammMaxPrice'), borsh_1.u64('ammMiddlePrice'), borsh_1.u64('ammPriceMultiplier'), // Fees borsh_1.u64('minSeparateNumerator'), borsh_1.u64('minSeparateDenominator'), borsh_1.u64('tradeFeeNumerator'), borsh_1.u64('tradeFeeDenominator'), borsh_1.u64('pnlNumerator'), borsh_1.u64('pnlDenominator'), borsh_1.u64('swapFeeNumerator'), borsh_1.u64('swapFeeDenominator'), // OutPutData borsh_1.u64('needTakePnlCoin'), borsh_1.u64('needTakePnlPc'), borsh_1.u64('totalPnlPc'), borsh_1.u64('totalPnlCoin'), borsh_1.u128('poolTotalDepositPc'), borsh_1.u128('poolTotalDepositCoin'), borsh_1.u128('swapCoinInAmount'), borsh_1.u128('swapPcOutAmount'), borsh_1.u128('swapPcInAmount'), borsh_1.u128('swapCoinOutAmount'), borsh_1.u64('swapPcFee'), borsh_1.u64('swapCoinFee'), borsh_1.publicKey('poolCoinTokenAccount'), borsh_1.publicKey('poolPcTokenAccount'), borsh_1.publicKey('coinMintAddress'), borsh_1.publicKey('pcMintAddress'), borsh_1.publicKey('lpMintAddress'), borsh_1.publicKey('ammOpenOrders'), borsh_1.publicKey('serumMarket'), borsh_1.publicKey('serumProgramId'), borsh_1.publicKey('ammTargetOrders'), borsh_1.publicKey('poolWithdrawQueue'), borsh_1.publicKey('poolTempLpTokenAccount'), borsh_1.publicKey('ammOwner'), borsh_1.publicKey('pnlOwner'), borsh_1.u128('currentK'), borsh_1.u128('padding1'), borsh_1.publicKey('padding2'), ]); function getLpMintInfo(conn, mintAddress, coin, pc) { var _a, _b; return __awaiter(this, void 0, void 0, function* () { let lpInfo = Object.values(tokens_1.LP_TOKENS).find((item) => item.mintAddress === mintAddress); if (!lpInfo) { const mintAll = yield web3_1.getMultipleAccounts(conn, [new web3_js_1.PublicKey(mintAddress)], web3_1.commitment); if (mintAll !== null) { const data = Buffer.from((_b = (_a = mintAll[0]) === null || _a === void 0 ? void 0 : _a.account.data) !== null && _b !== void 0 ? _b : ''); const mintLayoutData = layouts_1.MINT_LAYOUT.decode(data); lpInfo = { symbol: 'unknown', name: 'unknown', coin, pc, mintAddress: mintAddress, decimals: mintLayoutData.decimals, }; } } return lpInfo; }); } exports.getLpMintInfo = getLpMintInfo; function getLpMintListDecimals(conn, mintAddressInfos) { return __awaiter(this, void 0, void 0, function* () { const reLpInfoDict = {}; const mintList = []; mintAddressInfos.forEach((item) => { let lpInfo = Object.values(tokens_1.LP_TOKENS).find((itemLpToken) => itemLpToken.mintAddress === item); if (!lpInfo) { mintList.push(new web3_js_1.PublicKey(item)); lpInfo = { decimals: null, }; } reLpInfoDict[item] = lpInfo.decimals; }); const mintAll = yield web3_1.getMultipleAccounts(conn, mintList, web3_1.commitment); for (let mintIndex = 0; mintIndex < mintAll.length; mintIndex += 1) { const itemMint = mintAll[mintIndex]; if (itemMint) { const mintLayoutData = layouts_1.MINT_LAYOUT.decode(Buffer.from(itemMint.account.data)); reLpInfoDict[mintList[mintIndex].toString()] = mintLayoutData.decimals; } } const reInfo = {}; for (const key of Object.keys(reLpInfoDict)) { if (reLpInfoDict[key] !== null) { reInfo[key] = reLpInfoDict[key]; } } return reInfo; }); } exports.getLpMintListDecimals = getLpMintListDecimals; function getLiquidityInfoSimilar(ammIdOrMarket, from, to) { // const fromCoin = from === NATIVE_SOL.mintAddress ? TOKENS.WSOL.mintAddress : from // const toCoin = to === NATIVE_SOL.mintAddress ? TOKENS.WSOL.mintAddress : to const fromCoin = from === tokens_1.TOKENS.WSOL.mintAddress ? tokens_1.NATIVE_SOL.mintAddress : from; const toCoin = to === tokens_1.TOKENS.WSOL.mintAddress ? tokens_1.NATIVE_SOL.mintAddress : to; const knownLiquidity = pools_1.LIQUIDITY_POOLS.find((item) => { if (fromCoin !== undefined && toCoin != undefined && fromCoin === toCoin) { return false; } if (ammIdOrMarket !== undefined && !(item.ammId === ammIdOrMarket || item.serumMarket === ammIdOrMarket)) { return false; } if (fromCoin && item.pc.mintAddress !== fromCoin && item.coin.mintAddress !== fromCoin) { return false; } if (toCoin && item.pc.mintAddress !== toCoin && item.coin.mintAddress !== toCoin) { return false; } if (ammIdOrMarket || (fromCoin && toCoin)) { return true; } return false; }); return knownLiquidity; } exports.getLiquidityInfoSimilar = getLiquidityInfoSimilar; function getLiquidityInfo(from, to) { const fromCoin = from === tokens_1.TOKENS.WSOL.mintAddress ? tokens_1.NATIVE_SOL.mintAddress : from; const toCoin = to === tokens_1.TOKENS.WSOL.mintAddress ? tokens_1.NATIVE_SOL.mintAddress : to; return pools_1.LIQUIDITY_POOLS.filter((item) => item.version === 4 && ((item.coin.mintAddress === fromCoin && item.pc.mintAddress === toCoin) || (item.coin.mintAddress === toCoin && item.pc.mintAddress === fromCoin))); } exports.getLiquidityInfo = getLiquidityInfo; function requestInfos(conn) { var _a; return __awaiter(this, void 0, void 0, function* () { // commit('setLoading', true) let ammAll = []; let marketAll = []; yield Promise.all([ yield (() => __awaiter(this, void 0, void 0, function* () { ammAll = yield web3_1.getFilteredProgramAccounts(conn, new web3_js_1.PublicKey(ids_1.LIQUIDITY_POOL_PROGRAM_ID_V4), [ { dataSize: exports.AMM_INFO_LAYOUT_V4.span, }, ]); }))(), yield (() => __awaiter(this, void 0, void 0, function* () { marketAll = yield web3_1.getFilteredProgramAccounts(conn, new web3_js_1.PublicKey(ids_1.SERUM_PROGRAM_ID_V3), [ { dataSize: serum_1.MARKET_STATE_LAYOUT_V2.span, }, ]); }))(), ]); const marketToLayout = {}; marketAll.forEach((item) => { marketToLayout[item.publicKey.toString()] = serum_1.MARKET_STATE_LAYOUT_V2.decode(item.accountInfo.data); }); const lpMintAddressList = []; ammAll.forEach((item) => { const ammLayout = exports.AMM_INFO_LAYOUT_V4.decode(Buffer.from(item.accountInfo.data)); if (ammLayout.pcMintAddress.toString() === ammLayout.serumMarket.toString() || ammLayout.lpMintAddress.toString() === '11111111111111111111111111111111') { return; } lpMintAddressList.push(ammLayout.lpMintAddress.toString()); }); const lpMintListDecimls = yield getLpMintListDecimals(conn, lpMintAddressList); for (let indexAmmInfo = 0; indexAmmInfo < ammAll.length; indexAmmInfo += 1) { const ammInfo = exports.AMM_INFO_LAYOUT_V4.decode(Buffer.from(ammAll[indexAmmInfo].accountInfo.data)); if (!Object.keys(lpMintListDecimls).includes(ammInfo.lpMintAddress.toString()) || ammInfo.pcMintAddress.toString() === ammInfo.serumMarket.toString() || ammInfo.lpMintAddress.toString() === '11111111111111111111111111111111' || !Object.keys(marketToLayout).includes(ammInfo.serumMarket.toString())) { continue; } const fromCoin = ammInfo.coinMintAddress.toString() === tokens_1.TOKENS.WSOL.mintAddress ? tokens_1.NATIVE_SOL.mintAddress : ammInfo.coinMintAddress.toString(); const toCoin = ammInfo.pcMintAddress.toString() === tokens_1.TOKENS.WSOL.mintAddress ? tokens_1.NATIVE_SOL.mintAddress : ammInfo.pcMintAddress.toString(); let coin = Object.values(tokens_1.TOKENS).find((item) => item.mintAddress === fromCoin); if (!coin && fromCoin !== tokens_1.NATIVE_SOL.mintAddress) { tokens_1.TOKENS[`unknow-${ammInfo.coinMintAddress.toString()}`] = { symbol: 'unknown', name: 'unknown', mintAddress: ammInfo.coinMintAddress.toString(), decimals: layouts_1.getBigNumber(ammInfo.coinDecimals), cache: true, tags: [], }; coin = tokens_1.TOKENS[`unknow-${ammInfo.coinMintAddress.toString()}`]; } else if (fromCoin === tokens_1.NATIVE_SOL.mintAddress) { coin = tokens_1.NATIVE_SOL; } if (!coin.tags.includes('unofficial')) { coin.tags.push('unofficial'); } let pc = Object.values(tokens_1.TOKENS).find((item) => item.mintAddress === toCoin); if (!pc && toCoin !== tokens_1.NATIVE_SOL.mintAddress) { tokens_1.TOKENS[`unknow-${ammInfo.pcMintAddress.toString()}`] = { symbol: 'unknown', name: 'unknown', mintAddress: ammInfo.pcMintAddress.toString(), decimals: layouts_1.getBigNumber(ammInfo.pcDecimals), cache: true, tags: [], }; pc = tokens_1.TOKENS[`unknow-${ammInfo.pcMintAddress.toString()}`]; } else if (toCoin === tokens_1.NATIVE_SOL.mintAddress) { pc = tokens_1.NATIVE_SOL; } if (!pc.tags.includes('unofficial')) { pc.tags.push('unofficial'); } if (coin.mintAddress === tokens_1.TOKENS.WSOL.mintAddress) { coin.symbol = 'SOL'; coin.name = 'SOL'; coin.mintAddress = '11111111111111111111111111111111'; } if (pc.mintAddress === tokens_1.TOKENS.WSOL.mintAddress) { pc.symbol = 'SOL'; pc.name = 'SOL'; pc.mintAddress = '11111111111111111111111111111111'; } const lp = (_a = Object.values(tokens_1.LP_TOKENS).find((item) => item.mintAddress === ammInfo.lpMintAddress)) !== null && _a !== void 0 ? _a : { symbol: `${coin.symbol}-${pc.symbol}`, name: `${coin.symbol}-${pc.symbol}`, coin, pc, mintAddress: ammInfo.lpMintAddress.toString(), decimals: lpMintListDecimls[ammInfo.lpMintAddress], }; const { publicKey } = yield web3_1.createAmmAuthority(new web3_js_1.PublicKey(ids_1.LIQUIDITY_POOL_PROGRAM_ID_V4)); const market = marketToLayout[ammInfo.serumMarket]; const serumVaultSigner = yield web3_js_1.PublicKey.createProgramAddress([ammInfo.serumMarket.toBuffer(), market.vaultSignerNonce.toArrayLike(Buffer, 'le', 8)], new web3_js_1.PublicKey(ids_1.SERUM_PROGRAM_ID_V3)); const itemLiquidity = { name: `${coin.symbol}-${pc.symbol}`, coin, pc, lp, version: 4, programId: ids_1.LIQUIDITY_POOL_PROGRAM_ID_V4, ammId: ammAll[indexAmmInfo].publicKey.toString(), ammAuthority: publicKey.toString(), ammOpenOrders: ammInfo.ammOpenOrders.toString(), ammTargetOrders: ammInfo.ammTargetOrders.toString(), ammQuantities: tokens_1.NATIVE_SOL.mintAddress, poolCoinTokenAccount: ammInfo.poolCoinTokenAccount.toString(), poolPcTokenAccount: ammInfo.poolPcTokenAccount.toString(), poolWithdrawQueue: ammInfo.poolWithdrawQueue.toString(), poolTempLpTokenAccount: ammInfo.poolTempLpTokenAccount.toString(), serumProgramId: ids_1.SERUM_PROGRAM_ID_V3, serumMarket: ammInfo.serumMarket.toString(), serumBids: market.bids.toString(), serumAsks: market.asks.toString(), serumEventQueue: market.eventQueue.toString(), serumCoinVaultAccount: market.baseVault.toString(), serumPcVaultAccount: market.quoteVault.toString(), serumVaultSigner: serumVaultSigner.toString(), official: false, }; if (!pools_1.LIQUIDITY_POOLS.find((item) => item.ammId === itemLiquidity.ammId)) { pools_1.LIQUIDITY_POOLS.push(itemLiquidity); } else { for (let itemIndex = 0; itemIndex < pools_1.LIQUIDITY_POOLS.length; itemIndex += 1) { if (pools_1.LIQUIDITY_POOLS[itemIndex].ammId === itemLiquidity.ammId && pools_1.LIQUIDITY_POOLS[itemIndex].name !== itemLiquidity.name && !pools_1.LIQUIDITY_POOLS[itemIndex].official) { pools_1.LIQUIDITY_POOLS[itemIndex] = itemLiquidity; } } } } const liquidityPools = {}; const publicKeys = []; pools_1.LIQUIDITY_POOLS.forEach((pool) => { const { poolCoinTokenAccount, poolPcTokenAccount, ammOpenOrders, ammId, coin, pc, lp } = pool; publicKeys.push(new web3_js_1.PublicKey(poolCoinTokenAccount), new web3_js_1.PublicKey(poolPcTokenAccount), new web3_js_1.PublicKey(ammOpenOrders), new web3_js_1.PublicKey(ammId), new web3_js_1.PublicKey(lp.mintAddress)); const poolInfo = lodash_1.cloneDeep(pool); poolInfo.coin.balance = new safe_math_1.TokenAmount(0, coin.decimals); poolInfo.pc.balance = new safe_math_1.TokenAmount(0, pc.decimals); liquidityPools[lp.mintAddress] = poolInfo; }); const multipleInfo = yield web3_1.getMultipleAccounts(conn, publicKeys, web3_1.commitment); multipleInfo.forEach((info) => { if (info) { const address = info.publicKey.toBase58(); const data = Buffer.from(info.account.data); const { key, lpMintAddress, version } = pools_1.getAddressForWhat(address); if (key && lpMintAddress) { const poolInfo = liquidityPools[lpMintAddress]; switch (key) { case 'poolCoinTokenAccount': { const parsed = layouts_1.ACCOUNT_LAYOUT.decode(data); // quick fix: Number can only safely store up to 53 bits poolInfo.coin.balance.wei = poolInfo.coin.balance.wei.plus(layouts_1.getBigNumber(parsed.amount)); break; } case 'poolPcTokenAccount': { const parsed = layouts_1.ACCOUNT_LAYOUT.decode(data); poolInfo.pc.balance.wei = poolInfo.pc.balance.wei.plus(layouts_1.getBigNumber(parsed.amount)); break; } case 'ammOpenOrders': { const OPEN_ORDERS_LAYOUT = serum_1.OpenOrders.getLayout(new web3_js_1.PublicKey(poolInfo.serumProgramId)); const parsed = OPEN_ORDERS_LAYOUT.decode(data); const { baseTokenTotal, quoteTokenTotal } = parsed; poolInfo.coin.balance.wei = poolInfo.coin.balance.wei.plus(layouts_1.getBigNumber(baseTokenTotal)); poolInfo.pc.balance.wei = poolInfo.pc.balance.wei.plus(layouts_1.getBigNumber(quoteTokenTotal)); break; } case 'ammId': { let parsed; if (version === 2) { parsed = exports.AMM_INFO_LAYOUT.decode(data); } else if (version === 3) { parsed = exports.AMM_INFO_LAYOUT_V3.decode(data); } else { if (version === 5) { parsed = exports.AMM_INFO_LAYOUT_STABLE.decode(data); poolInfo.currentK = layouts_1.getBigNumber(parsed.currentK); } else parsed = exports.AMM_INFO_LAYOUT_V4.decode(data); const { swapFeeNumerator, swapFeeDenominator } = parsed; poolInfo.fees = { swapFeeNumerator: layouts_1.getBigNumber(swapFeeNumerator), swapFeeDenominator: layouts_1.getBigNumber(swapFeeDenominator), }; } const { status, needTakePnlCoin, needTakePnlPc } = parsed; poolInfo.status = layouts_1.getBigNumber(status); poolInfo.coin.balance.wei = poolInfo.coin.balance.wei.minus(layouts_1.getBigNumber(needTakePnlCoin)); poolInfo.pc.balance.wei = poolInfo.pc.balance.wei.minus(layouts_1.getBigNumber(needTakePnlPc)); break; } // getLpSupply case 'lpMintAddress': { const parsed = layouts_1.MINT_LAYOUT.decode(data); poolInfo.lp.totalSupply = new safe_math_1.TokenAmount(layouts_1.getBigNumber(parsed.supply), poolInfo.lp.decimals); break; } } } } }); return liquidityPools; }); } exports.requestInfos = requestInfos;