UNPKG

aftermath-ts-sdk

Version:
1,239 lines (1,233 loc) 933 kB
var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/general/apiHelpers/dynamicFieldsApiHelpers.ts var _DynamicFieldsApiHelpers, DynamicFieldsApiHelpers; var init_dynamicFieldsApiHelpers = __esm({ "src/general/apiHelpers/dynamicFieldsApiHelpers.ts"() { "use strict"; _DynamicFieldsApiHelpers = class _DynamicFieldsApiHelpers { // ========================================================================= // Constructor // ========================================================================= constructor(api) { this.api = api; // ========================================================================= // Public Methods // ========================================================================= // ========================================================================= // Dynamic Fields // ========================================================================= this.fetchCastDynamicFieldsOfTypeWithCursor = async (inputs) => { const { dynamicFields, nextCursor } = await this.fetchDynamicFieldsOfTypeWithCursor(inputs); const dynamicFieldObjectIds = dynamicFields.map((field) => field.objectId); const dynamicFieldObjects = await inputs.objectsFromObjectIds( dynamicFieldObjectIds ); return { dynamicFieldObjects, nextCursor }; }; this.fetchAllDynamicFieldsOfType = async (inputs) => { let allDynamicFields = []; let cursor; do { const dynamicFieldsWithCursor = await this.fetchDynamicFieldsOfTypeWithCursor({ ...inputs, cursor, limit: inputs.limitStepSize ?? _DynamicFieldsApiHelpers.constants.defaultLimitStepSize }); const dynamicFields = dynamicFieldsWithCursor.dynamicFields; allDynamicFields = [...allDynamicFields, ...dynamicFields]; if (dynamicFields.length === 0 || dynamicFieldsWithCursor.nextCursor === null) { return allDynamicFields; } cursor = dynamicFieldsWithCursor.nextCursor; } while (true); }; this.fetchCastAllDynamicFieldsOfType = async (inputs) => { const dynamicFields = await this.fetchAllDynamicFieldsOfType(inputs); const dynamicFieldObjectIds = dynamicFields.map((field) => field.objectId); const dynamicFieldObjects = await inputs.objectsFromObjectIds( dynamicFieldObjectIds ); return dynamicFieldObjects; }; this.fetchDynamicFieldsUntil = async (inputs) => { const { fetchFunc, isComplete, cursor, limitStepSize } = inputs; let allDynamicFields = []; let currentCursor = cursor ?? null; do { const dynamicFieldsWithCursor = await fetchFunc({ cursor: currentCursor ?? void 0, limit: limitStepSize ?? _DynamicFieldsApiHelpers.constants.defaultLimitStepSize }); const fetchedDynamicFields = dynamicFieldsWithCursor.dynamicFieldObjects; const nextCursor = dynamicFieldsWithCursor.nextCursor; allDynamicFields = [...allDynamicFields, ...fetchedDynamicFields]; if (fetchedDynamicFields.length === 0 || nextCursor === null) { return { dynamicFieldObjects: allDynamicFields, nextCursor }; } if (isComplete(allDynamicFields)) { return { dynamicFieldObjects: allDynamicFields, nextCursor }; } currentCursor = dynamicFieldsWithCursor.nextCursor; } while (true); }; this.fetchDynamicFieldsOfTypeWithCursor = async (inputs) => { const { parentObjectId, dynamicFieldType } = inputs; const dynamicFieldsResponse = await this.api.client.getDynamicFields({ ...inputs, limit: inputs.limit ?? _DynamicFieldsApiHelpers.constants.defaultLimitStepSize, parentId: parentObjectId }); const dynamicFields = dynamicFieldType === void 0 ? dynamicFieldsResponse.data : dynamicFieldsResponse.data.filter( (dynamicField) => typeof dynamicFieldType === "string" ? dynamicField.objectType === dynamicFieldType : dynamicFieldType(dynamicField.objectType) ); const nextCursor = dynamicFieldsResponse.nextCursor; return { dynamicFields, nextCursor }; }; // ========================================================================= // Dynamic Field Objects // ========================================================================= this.fetchDynamicFieldObject = (inputs) => { return this.api.client.getDynamicFieldObject(inputs); }; } }; // ========================================================================= // Private Static Constants // ========================================================================= _DynamicFieldsApiHelpers.constants = { defaultLimitStepSize: 256 }; DynamicFieldsApiHelpers = _DynamicFieldsApiHelpers; } }); // src/general/apiHelpers/eventsApiHelpers.ts var _EventsApiHelpers, EventsApiHelpers; var init_eventsApiHelpers = __esm({ "src/general/apiHelpers/eventsApiHelpers.ts"() { "use strict"; _EventsApiHelpers = class _EventsApiHelpers { // ========================================================================= // Constructor // ========================================================================= constructor(api) { this.api = api; // ========================================================================= // Public Methods // ========================================================================= // ========================================================================= // Fetching // ========================================================================= // TODO: make this filter by looking ONLY at all relevant AF packages // TODO: move to wallet package ? /** * @deprecated `subscribeEvent` was removed from `SuiJsonRpcClient` in * `@mysten/sui` v2. Poll `queryEvents` instead or use a WebSocket transport. */ this.fetchSubscribeToUserEvents = async (_inputs) => { throw new Error( "fetchSubscribeToUserEvents is not supported in @mysten/sui v2. subscribeEvent was removed from SuiJsonRpcClient. Poll queryEvents instead or use a WebSocket transport." ); }; this.fetchCastEventsWithCursor = async (inputs) => { const { query, eventFromEventOnChain, cursor, limit } = inputs; const fetchedEvents = await this.api.client.queryEvents({ query, cursor: cursor ? { ...cursor, eventSeq: cursor.eventSeq.toString() } : void 0, limit }); const events = fetchedEvents.data.map( eventFromEventOnChain ); return { events, nextCursor: fetchedEvents.nextCursor ?? null }; }; // TODO: make this function use timestamp passing as one of event filter args this.fetchEventsWithinTime = async (inputs) => { const { fetchEventsFunc, timeMs, limitStepSize } = inputs; const limit = limitStepSize ?? _EventsApiHelpers.constants.defaultLimitStepSize; const eventsWithinTime = []; let cursor; for (let loopCount = 0; loopCount < _EventsApiHelpers.constants.maxLoops; loopCount++) { const { events, nextCursor } = await fetchEventsFunc({ cursor, limit }); const now = Date.now(); const endIndex = events.findIndex( (event) => event.timestamp !== void 0 && now - event.timestamp > timeMs ); eventsWithinTime.push( ...endIndex < 0 ? events : events.slice(0, endIndex) ); if (events.length === 0 || nextCursor === null || endIndex >= 0) { return eventsWithinTime; } cursor = nextCursor; } return eventsWithinTime; }; this.fetchAllEvents = async (inputs) => { const { fetchEventsFunc, limitStepSize } = inputs; const limit = limitStepSize ?? _EventsApiHelpers.constants.defaultLimitStepSize; const allEvents = []; let cursor; let done = false; while (!done) { const { events, nextCursor } = await fetchEventsFunc({ cursor, limit }); allEvents.push(...events); if (events.length === 0 || nextCursor === null) { done = true; } else { cursor = nextCursor; } } return allEvents; }; } }; // ========================================================================= // Private Static Constants // ========================================================================= _EventsApiHelpers.constants = { defaultLimitStepSize: 256, maxLoops: 20 }; // ========================================================================= // Static Methods // ========================================================================= // ========================================================================= // Helpers // ========================================================================= _EventsApiHelpers.resolveEventType = (eventType) => typeof eventType === "string" ? eventType : eventType(); _EventsApiHelpers.suiEventOfTypeOrUndefined = (event, eventType) => event.type.includes(_EventsApiHelpers.resolveEventType(eventType)) ? event : void 0; _EventsApiHelpers.castEventOfTypeOrUndefined = (event, eventType, castFunction, exactMatch) => { const resolved = _EventsApiHelpers.resolveEventType(eventType); const matches = exactMatch ? event.type === resolved : event.type.includes(resolved); if (!matches) { return void 0; } return castFunction(event); }; _EventsApiHelpers.findCastEventsOrUndefined = (inputs) => { const { events, eventType, castFunction } = inputs; const resolved = _EventsApiHelpers.resolveEventType(eventType); return events.filter((event) => event.type.includes(resolved)).map((event) => castFunction(event)); }; _EventsApiHelpers.findCastEventOrUndefined = (inputs) => { return _EventsApiHelpers.findCastEventsOrUndefined(inputs)[0]; }; _EventsApiHelpers.findCastEventInTransactionOrUndefined = (transaction, eventType, castFunction) => { return _EventsApiHelpers.findCastEventOrUndefined({ events: transaction.events ?? [], eventType, castFunction }); }; _EventsApiHelpers.findCastEventInTransactionsOrUndefined = (transactions, eventType, castFunction) => { for (const transaction of transactions) { const event = _EventsApiHelpers.findCastEventInTransactionOrUndefined( transaction, eventType, castFunction ); if (event !== void 0) { return event; } } return void 0; }; _EventsApiHelpers.createEventType = (packageAddress, packageName, eventType, wrapperType) => { const innerType = `${packageAddress}::${packageName}::${eventType}`; return wrapperType ? `${wrapperType}<${innerType}>` : innerType; }; EventsApiHelpers = _EventsApiHelpers; } }); // src/general/apiHelpers/inspectionsApiHelpers.ts var _InspectionsApiHelpers, InspectionsApiHelpers; var init_inspectionsApiHelpers = __esm({ "src/general/apiHelpers/inspectionsApiHelpers.ts"() { "use strict"; _InspectionsApiHelpers = class _InspectionsApiHelpers { // ========================================================================= // Constructor // ========================================================================= constructor(api) { this.api = api; // ========================================================================= // Public Methods // ========================================================================= // ========================================================================= // Fetching // ========================================================================= // TODO: replace all bytes types with uint8array type this.fetchFirstBytesFromTxOutput = async (inputs) => { return (await this.fetchAllBytesFromTxOutput(inputs))[0]; }; this.fetchAllBytesFromTxOutput = async (inputs) => { const { allBytes } = await this.fetchAllBytesFromTx(inputs); return allBytes[allBytes.length - 1]; }; this.fetchAllBytesFromTx = async (inputs) => { const sender = inputs.sender ?? _InspectionsApiHelpers.constants.devInspectSigner; const response = await this.api.client.devInspectTransactionBlock({ sender, transactionBlock: inputs.tx }); if (response.effects.status.status === "failure") { throw new Error( response.effects.status.error ?? response.error ?? "dev inspect failed" ); } if (!response.results) { throw new Error("dev inspect move call returned no results"); } const resultBytes = response.results.map( (result) => result.returnValues?.map((val) => val[0]) ?? [] ); return { events: response.events, effects: response.effects, allBytes: resultBytes }; }; } }; _InspectionsApiHelpers.constants = { devInspectSigner: "0xacb7cb045c3afac61381cdf272cd24ebe115f86361c9f06490482c238765aeb5" }; InspectionsApiHelpers = _InspectionsApiHelpers; } }); // src/general/apiHelpers/objectsApiHelpers.ts var _ObjectsApiHelpers, ObjectsApiHelpers; var init_objectsApiHelpers = __esm({ "src/general/apiHelpers/objectsApiHelpers.ts"() { "use strict"; init_helpers(); _ObjectsApiHelpers = class _ObjectsApiHelpers { // ========================================================================= // Constructor // ========================================================================= constructor(api) { this.api = api; // ========================================================================= // Public Methods // ========================================================================= // ========================================================================= // Fetching // ========================================================================= this.fetchDoesObjectExist = async (objectId) => { const object = await this.api.client.getObject({ id: objectId }); return object.error === void 0; }; this.fetchIsObjectOwnedByAddress = async (inputs) => { const { objectId, walletAddress } = inputs; const object = await this.fetchObject({ objectId }); const objectOwner = object.data?.owner; if (!objectOwner || typeof objectOwner !== "object") { return false; } if ("AddressOwner" in objectOwner && objectOwner.AddressOwner === walletAddress) { return true; } if ("ObjectOwner" in objectOwner && objectOwner.ObjectOwner === walletAddress) { return true; } return false; }; this.fetchObjectsOfTypeOwnedByAddress = async (inputs) => { return this.fetchOwnedObjects({ ...inputs, filter: { StructType: Helpers.stripLeadingZeroesFromType(inputs.objectType) } }); }; this.fetchOwnedObjects = async (inputs) => { const { walletAddress, withDisplay, filter } = inputs; let allObjectData = []; let cursor; do { const paginatedObjects = await this.api.client.getOwnedObjects({ owner: walletAddress, options: inputs.options ?? { showContent: true, showDisplay: withDisplay, showOwner: true, showType: true }, limit: _ObjectsApiHelpers.constants.maxObjectFetchingLimit, cursor, filter }); const objectData = paginatedObjects.data; allObjectData = [...allObjectData, ...objectData]; if (paginatedObjects.data.length === 0 || !paginatedObjects.hasNextPage || !paginatedObjects.nextCursor) { return allObjectData; } cursor = paginatedObjects.nextCursor; } while (true); }; this.fetchObject = async (inputs) => { const { objectId, withDisplay } = inputs; return await this.fetchObjectGeneral({ objectId, options: { showContent: true, showDisplay: withDisplay, showOwner: true, showType: true } }); }; this.fetchObjectGeneral = async (inputs) => { const { objectId, options } = inputs; const object = await this.api.client.getObject({ id: objectId, options }); if (object.error !== void 0) { throw new Error( `an error occured fetching object: ${object.error?.code}` ); } return object; }; this.fetchCastObject = async (inputs) => { return inputs.objectFromSuiObjectResponse(await this.fetchObject(inputs)); }; this.fetchCastObjectGeneral = async (inputs) => { const { objectId, objectFromSuiObjectResponse, options } = inputs; return objectFromSuiObjectResponse( await this.fetchObjectGeneral({ objectId, options }) ); }; this.fetchObjectBatch = async (inputs) => { const { objectIds, options } = inputs; const objectIdsBatches = []; let endIndex = 0; while (true) { const newEndIndex = endIndex + _ObjectsApiHelpers.constants.maxObjectFetchingLimit; if (newEndIndex >= objectIds.length) { objectIdsBatches.push(objectIds.slice(endIndex, objectIds.length)); break; } objectIdsBatches.push(objectIds.slice(endIndex, newEndIndex)); endIndex = newEndIndex; } const objectBatches = await Promise.all( objectIdsBatches.map( (objectIds2) => this.api.client.multiGetObjects({ ids: objectIds2, options: options === void 0 ? { showContent: true, showOwner: true, showType: true } : options }) ) ); const objectBatch = objectBatches.reduce( (acc, objects) => [...acc, ...objects], [] ); return objectBatch; }; this.fetchCastObjectBatch = async (inputs) => { return (await this.fetchObjectBatch(inputs)).map( (SuiObjectResponse) => { return inputs.objectFromSuiObjectResponse(SuiObjectResponse); } ); }; this.fetchCastObjectsOwnedByAddressOfType = async (inputs) => { const objects = (await this.fetchObjectsOfTypeOwnedByAddress(inputs)).map( (SuiObjectResponse) => { return inputs.objectFromSuiObjectResponse(SuiObjectResponse); } ); return objects; }; // ========================================================================= // BCS // ========================================================================= this.fetchObjectBcs = async (objectId) => { const objectResponse = await this.api.client.getObject({ id: objectId, options: { showBcs: true } }); if (objectResponse.error !== void 0) { throw new Error( `an error occured fetching object: ${objectResponse.error?.code}` ); } return objectResponse; }; this.fetchCastObjectBcs = async (inputs) => { const { objectId } = inputs; const suiObjectResponse = await this.api.Objects().fetchObjectBcs(objectId); const { Casting: Casting2 } = await Promise.resolve().then(() => (init_casting(), casting_exports)); return Casting2.castObjectBcs({ ...inputs, suiObjectResponse }); }; // ========================================================================= // Transactions // ========================================================================= this.burnObjectTx = async (inputs) => { const { tx, object } = inputs; return tx.transferObjects( [object], // not using constants because of strange build bug on frontend otherwise // tx.pure(Sui.constants.addresses.zero) "0x0" ); }; this.publicShareObjectTx = async (inputs) => { const { tx, object, objectType } = inputs; return tx.moveCall({ target: Helpers.transactions.createTxTarget( // not using constants because of strange build bug on frontend otherwise // Sui.constants.addresses.suiPackageId, "0x2", "transfer", "public_share_object" ), typeArguments: [objectType], arguments: [object] }); }; } }; // ========================================================================= // Private Static Constants // ========================================================================= _ObjectsApiHelpers.constants = { maxObjectFetchingLimit: 50 }; ObjectsApiHelpers = _ObjectsApiHelpers; } }); // src/general/apiHelpers/transactionsApiHelpers.ts import { Transaction } from "@mysten/sui/transactions"; var _TransactionsApiHelpers, TransactionsApiHelpers; var init_transactionsApiHelpers = __esm({ "src/general/apiHelpers/transactionsApiHelpers.ts"() { "use strict"; init_helpers(); _TransactionsApiHelpers = class _TransactionsApiHelpers { // ========================================================================= // Constructor // ========================================================================= constructor(api) { this.api = api; // ========================================================================= // Public Methods // ========================================================================= // ========================================================================= // Fetching // ========================================================================= this.fetchTransactionsWithCursor = async (inputs) => { const { query, cursor, limit } = inputs; const transactionsWithCursor = await this.api.client.queryTransactionBlocks( { ...query, cursor, limit, options: { showEvents: true, showBalanceChanges: true, showEffects: true, showObjectChanges: true, showInput: true } } ); return { transactions: transactionsWithCursor.data, nextCursor: transactionsWithCursor.nextCursor ?? null }; }; this.fetchSetGasBudgetForTx = async (inputs) => { const { tx } = inputs; const [txResponse, referenceGasPrice] = await Promise.all([ this.api.client.dryRunTransactionBlock({ transactionBlock: await tx.build({ client: this.api.client }) }), this.api.client.getReferenceGasPrice() ]); const gasData = txResponse.effects.gasUsed; const gasUsed = BigInt(gasData.computationCost) + BigInt(gasData.storageCost); const safeGasBudget = gasUsed + gasUsed / BigInt(10); tx.setGasBudget(safeGasBudget); tx.setGasPrice(BigInt(referenceGasPrice)); return tx; }; this.fetchSetGasBudgetAndSerializeTx = async (inputs) => { const { tx, isSponsoredTx } = inputs; if (isSponsoredTx) { return (await tx).toJSON(); } return (await this.fetchSetGasBudgetForTx({ tx: await tx })).toJSON(); }; this.fetchBase64TxKindFromTx = async (inputs) => { const { tx } = inputs; if (!tx) { return; } const txBytes = await tx.build({ client: this.api?.client, onlyTransactionKind: true }); return Buffer.from(txBytes).toString("base64"); }; } static splitCoinTx(inputs) { const { tx, coinType, coinId, amount } = inputs; return tx.moveCall({ target: _TransactionsApiHelpers.createTxTarget( // Sui.constants.addresses.suiPackageId, "0x2", "coin", "split" ), typeArguments: [coinType], arguments: [ typeof coinId === "string" ? tx.object(coinId) : coinId, // Coin, tx.pure.u64(amount) // split_amount ] }); } }; // ========================================================================= // Public Static Methods // ========================================================================= // ========================================================================= // Helpers // ========================================================================= _TransactionsApiHelpers.createTxTarget = (packageAddress, packageName, functionName) => `${packageAddress}::${packageName}::${functionName}`; _TransactionsApiHelpers.createBuildTxFunc = (func) => { const builderFunc = (someInputs) => { const tx = new Transaction(); tx.setSender(someInputs.walletAddress); func({ tx, ...someInputs }); return tx; }; return builderFunc; }; _TransactionsApiHelpers.serviceCoinDataFromCoinTxArg = (inputs) => { const { coinTxArg } = inputs; if (typeof coinTxArg === "string") { return { Coin: Helpers.addLeadingZeroesToType(coinTxArg) }; } if (!("$kind" in coinTxArg)) { if (typeof coinTxArg === "function" || "GasCoin" in coinTxArg) { throw new Error("unable to convert gas coin arg to service coin data"); } return coinTxArg; } if (coinTxArg.$kind === "NestedResult") { return { [coinTxArg.$kind]: coinTxArg.NestedResult }; } if (coinTxArg.$kind === "Result") { return { [coinTxArg.$kind]: coinTxArg.Result }; } if (coinTxArg.$kind === "GasCoin") { throw new Error("unable to convert gas coin arg to service coin data"); } if (coinTxArg.$kind === "Input") { return { Input: coinTxArg.Input }; } throw new Error(`unexpected coinTxArg.$kind: ${coinTxArg.$kind}`); }; _TransactionsApiHelpers.serviceCoinDataV2FromCoinTxArg = (inputs) => { const { coinTxArg } = inputs; if (!("$kind" in coinTxArg)) { if ("Result" in coinTxArg) { return { Result: coinTxArg.Result }; } if ("NestedResult" in coinTxArg) { return { NestedResult: coinTxArg.NestedResult }; } if ("GasCoin" in coinTxArg) { return "Gas"; } if ("Input" in coinTxArg) { return { Input: coinTxArg.Input }; } throw new Error(`coinTxArg in format ${coinTxArg} not supported`); } if (coinTxArg.$kind === "NestedResult") { return { NestedResult: coinTxArg.NestedResult }; } if (coinTxArg.$kind === "Result") { return { Result: coinTxArg.Result }; } if (coinTxArg.$kind === "GasCoin") { return "Gas"; } if (coinTxArg.$kind === "Input") { return { Input: coinTxArg.Input }; } throw new Error(`unexpected coinTxArg.$kind: ${coinTxArg.$kind}`); }; _TransactionsApiHelpers.coinTxArgFromServiceCoinData = (inputs) => { const { serviceCoinData } = inputs; const key = Object.keys(serviceCoinData)[0]; if (key === "Coin") { throw new Error( "serviceCoinData in format { Coin: ObjectId } not supported" ); } const kind = key; if (kind === "NestedResult") { return { NestedResult: Object.values(serviceCoinData)[0] }; } if (kind === "Input") { return { Input: Object.values(serviceCoinData)[0] }; } return { Result: Object.values(serviceCoinData)[0] }; }; _TransactionsApiHelpers.coinTxArgFromServiceCoinDataV2 = (inputs) => { const { serviceCoinDataV2 } = inputs; if (typeof serviceCoinDataV2 === "string") { return { GasCoin: true }; } const key = Object.keys(serviceCoinDataV2)[0]; const value = Object.values(serviceCoinDataV2)[0]; const kind = key; if (kind === "Result" && typeof value === "number") { return { Result: value }; } if (kind === "NestedResult" && typeof value !== "number") { return { NestedResult: value }; } if (kind === "Input" && typeof value === "number") { return { Input: value }; } throw new Error( `serviceCoinDataV2 format ${JSON.stringify( serviceCoinDataV2 )} not supported` ); }; // public static mergeCoinsTx(inputs: { // tx: Transaction; // coinType: CoinType; // destinationCoinId: TransactionArgument | string; // sources: TransactionArgument[] | ObjectId[]; // }) { // const { tx, coinType, destinationCoinId, sources } = inputs; // // TODO: clean this up // const coinVec = // typeof sources[0] === "string" // ? tx.makeMoveVec({ // objects: sources.map((source) => // tx.object(source as ObjectId) // ), // type: `Coin<${coinType}>`, // }) // : sources; // return tx.moveCall({ // target: this.createTxTarget( // Sui.constants.addresses.suiPackageId, // "pay", // "join_vec" // ), // typeArguments: [coinType], // arguments: [ // typeof destinationCoinId === "string" // ? tx.object(destinationCoinId) // : destinationCoinId, // Coin, // // TODO: clean this up // // @ts-expect-error // coinVec, // coins // ], // }); // } _TransactionsApiHelpers.transferTxMetadata = (inputs) => { const { initTx, newTx } = inputs; const sender = initTx.getData().sender; if (sender) { newTx.setSender(sender); } const expiration = initTx.getData().expiration; if (expiration) { newTx.setExpiration(expiration); } const gasData = initTx.getData().gasData; if (gasData.budget && typeof gasData.budget !== "string") { newTx.setGasBudget(gasData.budget); } if (gasData.owner) { newTx.setGasOwner(gasData.owner); } if (gasData.payment) { newTx.setGasPayment(gasData.payment); } if (gasData.price && typeof gasData.price !== "string") { newTx.setGasPrice(gasData.price); } }; TransactionsApiHelpers = _TransactionsApiHelpers; } }); // src/general/utils/helpers.ts import { decodeSuiPrivateKey } from "@mysten/sui/cryptography"; import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519"; import { Secp256k1Keypair } from "@mysten/sui/keypairs/secp256k1"; import { Secp256r1Keypair } from "@mysten/sui/keypairs/secp256r1"; import { isValidSuiAddress } from "@mysten/sui/utils"; var NUMERIC_STRING_REGEX, BIGINT_STRING_REGEX, HEX_STRING_REGEX, _Helpers, Helpers; var init_helpers = __esm({ "src/general/utils/helpers.ts"() { "use strict"; init_dynamicFieldsApiHelpers(); init_eventsApiHelpers(); init_inspectionsApiHelpers(); init_objectsApiHelpers(); init_transactionsApiHelpers(); NUMERIC_STRING_REGEX = /^\d*\.?\d*$/; BIGINT_STRING_REGEX = /^-?\d+n$/; HEX_STRING_REGEX = /^(0x)?[0-9A-F]+$/i; _Helpers = class _Helpers { static uniqueObjectArray(arr) { const seen = /* @__PURE__ */ new Set(); return arr.filter((obj) => { const str = JSON.stringify(obj); if (seen.has(str)) { return false; } seen.add(str); return true; }); } /** * Combines two arrays into a single array of pairs. The result length is the * minimum of the two input arrays' lengths. * * @param firstCollection - The first array. * @param lastCollection - The second array. * @returns An array of `[firstCollection[i], lastCollection[i]]` pairs. */ static zip(firstCollection, lastCollection) { const length = Math.min(firstCollection.length, lastCollection.length); const zipped = []; for (let index = 0; index < length; index++) { zipped.push([firstCollection[index], lastCollection[index]]); } return zipped; } /** * Removes circular references from an object or array, returning a JSON-safe structure. * Any cyclic references are replaced with `undefined`. * * @param obj - The object or array to remove circular references from. * @param seen - Internal usage to track references that have already been visited. * @returns A structure that can be safely JSON-stringified. */ static removeCircularReferences(obj, seen = /* @__PURE__ */ new WeakSet()) { if (obj && typeof obj === "object") { if (seen.has(obj)) { return void 0; } seen.add(obj); if (Array.isArray(obj)) { return obj.map( (item) => _Helpers.removeCircularReferences(item, seen) ); } const entries = Object.entries(obj).map( ([key, value]) => [key, _Helpers.removeCircularReferences(value, seen)] ); return Object.fromEntries(entries); } return obj; } // ========================================================================= // Type Checking // ========================================================================= /** * Checks if an unknown value is an array of strings. * * @param value - The value to check. * @returns `true` if `value` is a string array, otherwise `false`. */ static isArrayOfStrings(value) { return Array.isArray(value) && value.every((item) => typeof item === "string"); } // ========================================================================= // Sui Object Parsing // ========================================================================= /** * Extracts the fully qualified type (e.g., "0x2::coin::Coin<...>") from a `SuiObjectResponse`, * normalizing it with leading zeroes if necessary. * * @param data - The object response from Sui. * @returns The normalized object type string. * @throws If the type is not found. */ static getObjectType(data) { const objectType = data.data?.type; if (objectType) { return _Helpers.addLeadingZeroesToType(objectType); } throw new Error(`no object type found on ${data.data?.objectId}`); } /** * Extracts the object ID from a `SuiObjectResponse`, normalizing it with leading zeroes. * * @param data - The object response from Sui. * @returns A zero-padded `ObjectId`. * @throws If the objectId is not found. */ static getObjectId(data) { const objectId = data.data?.objectId; if (objectId) { return _Helpers.addLeadingZeroesToType(objectId); } throw new Error(`no object id found on ${data.data?.type}`); } /** * Retrieves the fields of a Move object from a `SuiObjectResponse`. * * @param data - The Sui object response containing a Move object. * @returns A record of fields for that object. * @throws If no fields are found. */ // biome-ignore lint/suspicious/noExplicitAny: Move fields are dynamic — callers access nested properties directly; typing as `unknown` would cascade casts through dozens of call sites static getObjectFields(data) { try { const content = data.data?.content; return content.fields; } catch (_e) { throw new Error(`no object fields found on ${data.data?.objectId}`); } } /** * Retrieves display metadata from a Sui object response, if present. * * @param data - The Sui object response. * @returns The display fields for that object. * @throws If display fields are not found. */ static getObjectDisplay(data) { const display = data.data?.display; if (display) { return display; } throw new Error(`no object display found on ${data.data?.objectId}`); } // ========================================================================= // Error Parsing // ========================================================================= /** * Parses a MoveAbort error message from Sui into a possible `(errorCode, packageId, module)`, * if the message follows a known pattern. Otherwise returns undefined. * * @param inputs - The object containing the raw `errorMessage` from Sui. * @returns A partial structure of the error details or undefined. */ static parseMoveErrorMessage(inputs) { const { errorMessage } = inputs; if (!errorMessage.toLowerCase().includes("moveabort")) { return void 0; } const moveErrorCode = (errorMsg) => { const startIndex = errorMsg.lastIndexOf(","); const endIndex = errorMsg.lastIndexOf(")"); if (startIndex <= 0 || endIndex <= 0 || startIndex >= endIndex) { return void 0; } try { const errorCode2 = Number.parseInt( errorMsg.slice(startIndex + 1, endIndex), 10 ); if (Number.isNaN(errorCode2)) { return void 0; } return errorCode2; } catch { return void 0; } }; const moveErrorPackageId = (errorMsg) => { const startIndex = errorMsg.toLowerCase().indexOf("address:"); const endIndex = errorMsg.indexOf(", name:"); if (startIndex <= 0 || endIndex <= 0 || startIndex >= endIndex) { return void 0; } try { const pkgStr = errorMsg.slice(startIndex + 8, endIndex).trim().replaceAll("0x", ""); const packageId2 = _Helpers.addLeadingZeroesToType(`0x${pkgStr}`); if (!_Helpers.isValidHex(packageId2)) { return void 0; } return packageId2; } catch { return void 0; } }; const moveErrorModule = (errorMsg) => { const startIndex = errorMsg.toLowerCase().indexOf('identifier("'); const endIndex = errorMsg.indexOf('")'); if (startIndex <= 0 || endIndex <= 0 || startIndex >= endIndex) { return void 0; } try { return errorMsg.slice(startIndex + 12, endIndex).trim(); } catch { return void 0; } }; const errorCode = moveErrorCode(errorMessage); const packageId = moveErrorPackageId(errorMessage); const module = moveErrorModule(errorMessage); if (errorCode === void 0 || !packageId || !module) { return void 0; } return { errorCode, packageId, module }; } /** * Translates a Move abort error message into a known error string if it matches * entries in a given `moveErrors` table. This is used to map on-chain error codes * to user-friendly messages. * * @param inputs - Includes the raw `errorMessage` and a `moveErrors` object keyed by package, module, and code. * @returns A structure with `errorCode`, `packageId`, `module`, and a human-readable `error` string, or `undefined`. */ static translateMoveErrorMessage(inputs) { const { errorMessage, moveErrors } = inputs; const parsed = _Helpers.parseMoveErrorMessage({ errorMessage }); if (!(parsed && parsed.packageId in moveErrors)) { return void 0; } let error; if (parsed.module in moveErrors[parsed.packageId] && parsed.errorCode in moveErrors[parsed.packageId][parsed.module]) { error = moveErrors[parsed.packageId][parsed.module][parsed.errorCode]; } else if ("ANY" in moveErrors[parsed.packageId] && parsed.errorCode in moveErrors[parsed.packageId].ANY) { error = moveErrors[parsed.packageId].ANY[parsed.errorCode]; } else { return void 0; } return { ...parsed, error }; } }; // ========================================================================= // Api Helpers (Static References) // ========================================================================= /** * Static reference to the `DynamicFieldsApiHelpers`, providing utility methods * for working with dynamic fields in Sui objects. */ _Helpers.dynamicFields = DynamicFieldsApiHelpers; /** * Static reference to the `EventsApiHelpers`, providing methods for * querying and filtering Sui events. */ _Helpers.events = EventsApiHelpers; /** * Static reference to the `InspectionsApiHelpers`, used for reading * Summaries or inspection data from objects. */ _Helpers.inspections = InspectionsApiHelpers; /** * Static reference to the `ObjectsApiHelpers`, providing direct * retrieval or manipulation of on-chain Sui objects. */ _Helpers.objects = ObjectsApiHelpers; /** * Static reference to the `TransactionsApiHelpers`, enabling easier * queries for transaction data by digest or other criteria. */ _Helpers.transactions = TransactionsApiHelpers; // ========================================================================= // Type Manipulation // ========================================================================= /** * Removes all leading zeroes (after the '0x') from a string that represents * a Sui address or object type. For instance, "0x0000123" => "0x123". * * @param type - The hex string to process, potentially including "::" module syntax. * @returns The same string with unnecessary leading zeroes stripped out. */ _Helpers.stripLeadingZeroesFromType = (type) => type.replaceAll(/x0+/g, "x"); /** * Ensures the given Sui address or object type is zero-padded to 64 hex digits * after the "0x". If a "::" suffix is present, only the address portion is padded. * * @param type - The "0x..." string or extended type (0x..::module). * @returns A new string normalized to a 64-hex-digit address or object ID. * @throws If the address portion is already longer than 64 hex digits. */ _Helpers.addLeadingZeroesToType = (type) => { const EXPECTED_TYPE_LENGTH = 64; let strippedType = type.replace("0x", ""); let typeSuffix = ""; if (strippedType.includes("::")) { const splitType = strippedType.replace("0x", "").split("::"); typeSuffix = splitType.slice(1).reduce((acc, str) => `${acc}::${str}`, ""); strippedType = splitType[0]; } const typeLength = strippedType.length; if (typeLength > EXPECTED_TYPE_LENGTH) { throw new Error("invalid type length"); } const zerosNeeded = EXPECTED_TYPE_LENGTH - typeLength; const zeroString = "0".repeat(zerosNeeded); const newType = `0x${zeroString}${strippedType}`; return newType + typeSuffix; }; /** * Splits a non-SUI coin type string that may be prefixed by a chain ID for external usage, * returning the chain and the coin type. If no chain is recognized, defaults to `"sui"`. * * @param coin - The coin string, which may look like `"bsc:0x<...>"` or just `"0x<...>"`. * @returns An object with the `chain` (e.g. "bsc") and the `coinType`. */ _Helpers.splitNonSuiCoinType = (coin) => { const [uncastChain, coinType] = coin.split(":"); if (!(uncastChain && coinType)) { return { coinType: coin, chain: "sui" }; } const chain = uncastChain; return { chain, coinType }; }; // ========================================================================= // Numbers // ========================================================================= /** * Checks if a given string represents a valid number (integer or decimal). * * @param str - The string to test. * @returns `true` if it's a valid numeric string, otherwise `false`. */ _Helpers.isNumber = (str) => NUMERIC_STRING_REGEX.test(str); /** * Sums an array of floating-point numbers, returning the numeric total. * * @param arr - The array of numbers to sum. * @returns The total as a float. */ _Helpers.sum = (arr) => arr.reduce((prev, cur) => prev + cur, 0); /** * Sums an array of bigints, returning the total as a bigint. * * @param arr - The array of bigints to sum. * @returns The resulting total as a bigint. */ _Helpers.sumBigInt = (arr) => arr.reduce((prev, cur) => prev + cur, BigInt(0)); /** * Determines if two numbers are close within a given tolerance factor, * i.e., `|a - b| <= tolerance * max(a, b)`. * * @param a - The first number. * @param b - The second number. * @param tolerance - A fraction representing the max allowed difference relative to max(a, b). * @returns `true` if within tolerance, otherwise `false`. */ _Helpers.closeEnough = (a, b, tolerance) => Math.abs(a - b) <= tolerance * Math.max(a, b); /** * Determines if two bigints are close within a given tolerance factor, * by casting them to numbers internally. * * @param a - First bigint. * @param b - Second bigint. * @param tolerance - A fraction representing the max allowed difference relative to max(a, b). * @returns `true` if within tolerance, otherwise `false`. */ _Helpers.closeEnoughBigInt = (a, b, tolerance) => _Helpers.closeEnough(Number(a), Number(b), tolerance); /** * Checks whether the integer divisions of `a` and `b` (by `fixedOne`) differ * by at most 1. Typically used in fixed math scenarios to see if two scaled * values are "very close." * * @param a - First number (scaled). * @param b - Second number (scaled). * @param fixedOne - The scaling factor representing 1.0 in the same scale as `a` and `b`. * @returns `true` if the integer parts differ by <= 1, otherwise `false`. */ _Helpers.veryCloseInt = (a, b, fixedOne) => Math.abs(Math.floor(a / fixedOne) - Math.floor(b / fixedOne)) <= 1; /** * A small object containing "blended" math operations that handle * mixed numeric types (number vs. bigint). This is primarily for * internal usage in advanced math scenarios. */ _Helpers.blendedOperations = { /** * Multiply two floating-point numbers. */ mulNNN: (a, b) => a * b, /** * Multiply a float and a bigint, returning a bigint (floor). */ mulNNB: (a, b) => BigInt(Math.floor(a * b)), /** * Multiply a float and a bigint, returning a float. */ mulNBN: (a, b) => a * Number(b), /** * Multiply a float and a bigint, returning a bigint (floor). */ mulNBB: (a, b) => BigInt(Math.floor(a * Number(b))), /** * Multiply two bigints, returning a float. */ mulBBN: (a, b) => Number(a * b), /** * Multiply two bigints, returning a bigint. */ mul