UNPKG

@symmetry-hq/liquidity-sdk

Version:

Exchange functionality using symmetry funds liquidity

188 lines (187 loc) 9.08 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 __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; 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.TokenSwap = void 0; const anchor_1 = require("@coral-xyz/anchor"); const nodewallet_1 = __importDefault(require("@coral-xyz/anchor/dist/cjs/nodewallet")); const web3_js_1 = require("@solana/web3.js"); const types_1 = require("./types"); const fundsIDL_1 = require("./fundsIDL"); const decoder_1 = require("./decoder"); const executeSwap_1 = require("./executeSwap"); const liquidity_1 = require("./liquidity"); __exportStar(require("./types"), exports); class TokenSwap { constructor(accountInfos, connection, wallet) { let { tokenListAccountInfo, curveDataAccountInfo, oracleDataAccountInfos, fundStateAccountInfos, } = accountInfos; if (!wallet) wallet = new nodewallet_1.default(web3_js_1.Keypair.generate()); let provider = new anchor_1.AnchorProvider(connection, wallet, { skipPreflight: true, preflightCommitment: "confirmed", commitment: "confirmed", }); this.connection = connection; this.wallet = wallet; this.program = new anchor_1.Program(fundsIDL_1.IDL, types_1.FUNDS_PROGRAM_ID, provider); this.tokenListData = (0, decoder_1.decodeTokenList)(this.program, tokenListAccountInfo); this.curveChainData = (0, decoder_1.decodeCurveData)(this.program, curveDataAccountInfo); this.funds = (0, decoder_1.decodeFunds)(this.program, fundStateAccountInfos); this.oraclePrices = (0, decoder_1.decodeOraclePrices)(oracleDataAccountInfos, this.tokenListData); } static getAccountInfosForTokenSwap(connection) { return __awaiter(this, void 0, void 0, function* () { //@ts-ignore let [tokenListAccountInfo, curveDataAccountInfo] = yield connection .getMultipleAccountsInfo([types_1.TOKEN_LIST_ADDRESS, types_1.CURVE_DATA_ADDRESS]); let oracleDataPubkeys = []; let numTokens = new anchor_1.BN(tokenListAccountInfo.data.slice(8, 16), 10, "le").toNumber(); for (let i = 0; i < numTokens; i++) { let start = 199 * i + 16 + 96; let end = 199 * i + 16 + 96 + 32; oracleDataPubkeys.push(new web3_js_1.PublicKey(tokenListAccountInfo.data.slice(start, end))); } //@ts-ignore let oracleDataAccountInfos = yield connection .getMultipleAccountsInfo(oracleDataPubkeys); let fundStateAccountInfos = yield connection.getProgramAccounts(types_1.FUNDS_PROGRAM_ID, { commitment: connection.commitment, filters: [ { dataSize: 10208 }, { memcmp: { offset: 112, bytes: "11111111" } } ], encoding: 'base64' }); return { tokenListAccountInfo: tokenListAccountInfo, curveDataAccountInfo: curveDataAccountInfo, oracleDataAccountInfos: oracleDataAccountInfos, fundStateAccountInfos: fundStateAccountInfos, }; }); } static init(connection, wallet) { return __awaiter(this, void 0, void 0, function* () { return new TokenSwap(yield this.getAccountInfosForTokenSwap(connection), connection, wallet); }); } setWallet(wallet) { this.wallet = wallet; let provider = new anchor_1.AnchorProvider(this.connection, wallet, { skipPreflight: true, preflightCommitment: "confirmed", commitment: "confirmed", }); this.program = new anchor_1.Program(fundsIDL_1.IDL, types_1.FUNDS_PROGRAM_ID, provider); } getTokenList() { return this.tokenListData.filter(x => x.isLive == true).map(x => { return { tokenId: x.id, coingeckoId: x.coingeckoId, tokenMint: x.tokenMint, }; }); } getAccountsForUpdate() { return [ types_1.CURVE_DATA_ADDRESS, ...this.tokenListData.map(token => new web3_js_1.PublicKey(token.oracleAccount)), ...this.funds.map(fund => fund.pubkey), ]; } update(accountInfos) { this.curveChainData = (0, decoder_1.decodeCurveData)(this.program, accountInfos[0]); this.oraclePrices = (0, decoder_1.decodeOraclePrices)(accountInfos.slice(1, 1 + this.tokenListData.length), this.tokenListData); this.funds = (0, decoder_1.decodeFunds)(this.program, accountInfos.slice(1 + this.tokenListData.length, accountInfos.length) .map((info, id) => { return { pubkey: this.funds[id].pubkey, account: info, }; })); } updateLiquiditySources() { return __awaiter(this, void 0, void 0, function* () { let accounts = this.getAccountsForUpdate(); let results = []; for (let i = 0; i < accounts.length; i += 100) { //@ts-ignore let batch = yield this.connection .getMultipleAccountsInfo(accounts.slice(i, i + 100)); results = [...results, ...batch]; } this.update(results); }); } findTokenId(tokenMint) { for (let i = 0; i < this.tokenListData.length; i++) if (this.tokenListData[i].tokenMint == tokenMint.toBase58()) return this.tokenListData[i].id; return undefined; } getRouteData(tokenFrom, tokenTo, fromAmount) { let tokenIdFrom = this.findTokenId(tokenFrom); let tokenIdTo = this.findTokenId(tokenTo); return (0, liquidity_1.loadRouteData)(this.tokenListData, this.curveChainData, this.funds, this.oraclePrices, //@ts-ignore tokenIdFrom, tokenIdTo, fromAmount); } getAllRoutes(tokenFrom, tokenTo, fromAmount) { let tokenIdFrom = this.findTokenId(tokenFrom); let tokenIdTo = this.findTokenId(tokenTo); let possibleRoutes = this.funds .map(fund => (0, liquidity_1.checkForLiquidity)(this.tokenListData, this.curveChainData, fund.pubkey, fund.fund, this.oraclePrices, //@ts-ignore tokenIdFrom, tokenIdTo, //@ts-ignore Math.floor(fromAmount * 10 ** this.tokenListData[tokenIdFrom].decimals))); //@ts-ignore return possibleRoutes.filter(route => route != undefined).sort((a, b) => b.toAmount - a.toAmount); } executeSwap(routeData, fromTokenAccount, toTokenAccount, slippage) { return __awaiter(this, void 0, void 0, function* () { if (!this.wallet) throw new Error("Wallet not provided"); return yield (0, executeSwap_1.executeSwap)(this.program, //@ts-ignore this.wallet, this.connection, this.tokenListData, routeData, fromTokenAccount, toTokenAccount, slippage); }); } generateSwapInstruction(routeData, fromTokenAccount, toTokenAccount, user, slippage) { var _a; return __awaiter(this, void 0, void 0, function* () { if (!user && !this.wallet) throw new Error("Wallet not provided"); if (!user) user = (_a = this.wallet) === null || _a === void 0 ? void 0 : _a.publicKey; return yield (0, executeSwap_1.generateSwapInstruction)(this.program, //@ts-ignore user, this.tokenListData, routeData, fromTokenAccount, toTokenAccount, slippage); }); } } exports.TokenSwap = TokenSwap;