UNPKG

@mysten/sui

Version:

Sui TypeScript API(Work in Progress)

181 lines (180 loc) 6.14 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var CoinWithBalance_exports = {}; __export(CoinWithBalance_exports, { coinWithBalance: () => coinWithBalance }); module.exports = __toCommonJS(CoinWithBalance_exports); var import_valibot = require("valibot"); var import_bcs = require("../../bcs/index.js"); var import_sui_types = require("../../utils/sui-types.js"); var import_Commands = require("../Commands.js"); var import_Inputs = require("../Inputs.js"); var import_json_rpc_resolver = require("../json-rpc-resolver.js"); const COIN_WITH_BALANCE = "CoinWithBalance"; const SUI_TYPE = (0, import_sui_types.normalizeStructTag)("0x2::sui::SUI"); function coinWithBalance({ type = SUI_TYPE, balance, useGasCoin = true }) { let coinResult = null; return (tx) => { if (coinResult) { return coinResult; } tx.addIntentResolver(COIN_WITH_BALANCE, resolveCoinBalance); const coinType = type === "gas" ? type : (0, import_sui_types.normalizeStructTag)(type); coinResult = tx.add( import_Commands.Commands.Intent({ name: COIN_WITH_BALANCE, inputs: {}, data: { type: coinType === SUI_TYPE && useGasCoin ? "gas" : coinType, balance: BigInt(balance) } }) ); return coinResult; }; } const CoinWithBalanceData = (0, import_valibot.object)({ type: (0, import_valibot.string)(), balance: (0, import_valibot.bigint)() }); async function resolveCoinBalance(transactionData, buildOptions, next) { const coinTypes = /* @__PURE__ */ new Set(); const totalByType = /* @__PURE__ */ new Map(); if (!transactionData.sender) { throw new Error("Sender must be set to resolve CoinWithBalance"); } for (const command of transactionData.commands) { if (command.$kind === "$Intent" && command.$Intent.name === COIN_WITH_BALANCE) { const { type, balance } = (0, import_valibot.parse)(CoinWithBalanceData, command.$Intent.data); if (type !== "gas" && balance > 0n) { coinTypes.add(type); } totalByType.set(type, (totalByType.get(type) ?? 0n) + balance); } } const usedIds = /* @__PURE__ */ new Set(); for (const input of transactionData.inputs) { if (input.Object?.ImmOrOwnedObject) { usedIds.add(input.Object.ImmOrOwnedObject.objectId); } if (input.UnresolvedObject?.objectId) { usedIds.add(input.UnresolvedObject.objectId); } } const coinsByType = /* @__PURE__ */ new Map(); const client = (0, import_json_rpc_resolver.getClient)(buildOptions); await Promise.all( [...coinTypes].map(async (coinType) => { coinsByType.set( coinType, await getCoinsOfType({ coinType, balance: totalByType.get(coinType), client, owner: transactionData.sender, usedIds }) ); }) ); const mergedCoins = /* @__PURE__ */ new Map(); mergedCoins.set("gas", { $kind: "GasCoin", GasCoin: true }); for (const [index, transaction] of transactionData.commands.entries()) { if (transaction.$kind !== "$Intent" || transaction.$Intent.name !== COIN_WITH_BALANCE) { continue; } const { type, balance } = transaction.$Intent.data; if (balance === 0n && type !== "gas") { transactionData.replaceCommand( index, import_Commands.Commands.MoveCall({ target: "0x2::coin::zero", typeArguments: [type] }) ); continue; } const commands = []; if (!mergedCoins.has(type)) { const [first, ...rest] = coinsByType.get(type).map( (coin) => transactionData.addInput( "object", import_Inputs.Inputs.ObjectRef({ objectId: coin.coinObjectId, digest: coin.digest, version: coin.version }) ) ); if (rest.length > 0) { commands.push(import_Commands.Commands.MergeCoins(first, rest)); } mergedCoins.set(type, first); } commands.push( import_Commands.Commands.SplitCoins(mergedCoins.get(type), [ transactionData.addInput("pure", import_Inputs.Inputs.Pure(import_bcs.bcs.u64().serialize(balance))) ]) ); transactionData.replaceCommand(index, commands); transactionData.mapArguments((arg) => { if (arg.$kind === "Result" && arg.Result === index) { return { $kind: "NestedResult", NestedResult: [index + commands.length - 1, 0] }; } return arg; }); } return next(); } async function getCoinsOfType({ coinType, balance, client, owner, usedIds }) { let remainingBalance = balance; const coins = []; return loadMoreCoins(); async function loadMoreCoins(cursor = null) { const { data, hasNextPage, nextCursor } = await client.getCoins({ owner, coinType, cursor }); const sortedCoins = data.sort((a, b) => Number(BigInt(b.balance) - BigInt(a.balance))); for (const coin of sortedCoins) { if (usedIds.has(coin.coinObjectId)) { continue; } const coinBalance = BigInt(coin.balance); coins.push(coin); remainingBalance -= coinBalance; if (remainingBalance <= 0) { return coins; } } if (hasNextPage) { return loadMoreCoins(nextCursor); } throw new Error(`Not enough coins of type ${coinType} to satisfy requested balance`); } } //# sourceMappingURL=CoinWithBalance.js.map