aftermath-ts-sdk
Version:
Aftermath TypeScript SDK
1,239 lines (1,233 loc) • 933 kB
JavaScript
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