UNPKG

@bluefin-exchange/bluefin7k-aggregator-sdk

Version:
149 lines (148 loc) 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildTx = void 0; const transactions_1 = require("@mysten/sui/transactions"); const utils_1 = require("@mysten/sui/utils"); const config_1 = require("../../config"); const _7k_1 = require("../../constants/_7k"); const getSplitCoinForTx_1 = require("../../libs/getSplitCoinForTx"); const groupSwapRoutes_1 = require("../../libs/groupSwapRoutes"); const client_1 = require("../../libs/protocols/bluefinx/client"); const types_1 = require("../../libs/protocols/bluefinx/types"); const swapWithRoute_1 = require("../../libs/swapWithRoute"); const aggregator_1 = require("../../types/aggregator"); const sui_1 = require("../../utils/sui"); const token_1 = require("../../utils/token"); const config_2 = require("./config"); const buildTx = async ({ quoteResponse, accountAddress, slippage, commission: __commission, devInspect, extendTx, isSponsored, }) => { const isBluefinX = (0, aggregator_1.isBluefinXRouting)(quoteResponse); const _commission = { ...__commission, // commission is ignored for bluefinx commissionBps: isBluefinX ? 0 : __commission.commissionBps, }; const { tx: _tx, coinIn } = extendTx || {}; let coinOut; if (isBluefinX && devInspect) { throw new Error("BluefinX tx is sponsored, skip devInspect"); } if (!accountAddress) { throw new Error("Sender address is required"); } if (!quoteResponse.routes) { throw new Error("Invalid quote response: 'routes' are required"); } if (!(0, utils_1.isValidSuiAddress)(_commission.partner)) { throw new Error("Invalid commission partner address"); } const tx = _tx || new transactions_1.Transaction(); const routes = (0, groupSwapRoutes_1.groupSwapRoutes)(quoteResponse); const splits = routes.map((group) => group[0]?.amount ?? "0"); let coinData; if (coinIn) { coinData = tx.splitCoins(coinIn, splits); sui_1.SuiUtils.transferOrDestroyZeroCoin(tx, quoteResponse.tokenIn, coinIn, accountAddress); } else { const { coinData: _data } = await (0, getSplitCoinForTx_1.getSplitCoinForTx)(accountAddress, quoteResponse.swapAmountWithDecimal, splits, (0, token_1.denormalizeTokenType)(quoteResponse.tokenIn), tx, devInspect, isSponsored || isBluefinX); coinData = _data; } const pythMap = await updatePythPriceFeedsIfAny(tx, quoteResponse); const coinObjects = []; const config = await (0, config_2.getConfig)(); await Promise.all(routes.map(async (route, index) => { const inputCoinObject = coinData[index]; const coinRes = await (0, swapWithRoute_1.swapWithRoute)({ route, inputCoinObject, currentAccount: accountAddress, tx, config, pythMap, }); if (coinRes) { coinObjects.push(coinRes); } })); if (coinObjects.length > 0) { const mergeCoin = coinObjects.length > 1 ? sui_1.SuiUtils.mergeCoins(coinObjects, tx) : coinObjects[0]; const returnAmountAfterCommission = (BigInt(10000 - _commission.commissionBps) * BigInt(quoteResponse.returnAmountWithDecimal)) / BigInt(10000); const minReceived = (BigInt(1e9 - +slippage * 1e9) * BigInt(returnAmountAfterCommission)) / BigInt(1e9); tx.moveCall({ target: `${_7k_1._7K_PACKAGE_ID}::settle::settle`, typeArguments: [quoteResponse.tokenIn, quoteResponse.tokenOut], arguments: [ tx.object(_7k_1._7K_CONFIG), tx.object(_7k_1._7K_VAULT), tx.pure.u64(quoteResponse.swapAmountWithDecimal), mergeCoin, tx.pure.u64(minReceived), // minimum received tx.pure.u64(returnAmountAfterCommission), // expected amount out tx.pure.option("address", (0, utils_1.isValidSuiAddress)(_commission.partner) ? _commission.partner : null), tx.pure.u64(_commission.commissionBps), tx.pure.u64(0), ], }); if (!extendTx) { tx.transferObjects([mergeCoin], tx.pure.address(accountAddress)); } else { coinOut = mergeCoin; } } if (isBluefinX) { const extra = quoteResponse.swaps[0].extra; if (extra.quoteExpiresAtUtcMillis < Date.now()) { throw new Error("Quote expired"); } tx.setSenderIfNotSet(accountAddress); const bytes = await tx.build({ client: config_1.Config.getSuiClient(), onlyTransactionKind: true, }); const res = await (0, client_1.sponsorBluefinX)({ quoteId: extra.quoteId, txBytes: (0, utils_1.toBase64)(bytes), sender: accountAddress, }); if (!res.success) { throw new Error("Sponsor failed"); } return { tx: new types_1.BluefinXTx(res.quoteId, res.data.txBytes), coinOut, }; } return { tx, coinOut }; }; exports.buildTx = buildTx; const getPythPriceFeeds = (res) => { const ids = new Set(); for (const s of res.swaps) { for (const o of s.extra?.oracles || []) { const bytes = o.Pyth?.price_identifier?.bytes; if (bytes) { ids.add("0x" + (0, utils_1.toHex)(Uint8Array.from(bytes))); } } } return Array.from(ids); }; const updatePythPriceFeedsIfAny = async (tx, quoteResponse) => { // update oracles price if any const pythMap = {}; const pythIds = getPythPriceFeeds(quoteResponse); if (pythIds.length > 0) { const prices = await config_1.Config.getPythConnection().getPriceFeedsUpdateData(pythIds); const ids = await config_1.Config.getPythClient().updatePriceFeeds(tx, prices, pythIds); pythIds.map((id, index) => { pythMap[id] = ids[index]; }); } return pythMap; };