@bluefin-exchange/bluefin7k-aggregator-sdk
Version:
149 lines (148 loc) • 6.07 kB
JavaScript
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;
};
;