UNPKG

client-aftermath-ts-sdk

Version:
430 lines (429 loc) 18 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.Helpers = void 0; const dynamicFieldsApiHelpers_1 = require("../apiHelpers/dynamicFieldsApiHelpers"); const eventsApiHelpers_1 = require("../apiHelpers/eventsApiHelpers"); const inspectionsApiHelpers_1 = require("../apiHelpers/inspectionsApiHelpers"); const objectsApiHelpers_1 = require("../apiHelpers/objectsApiHelpers"); const transactionsApiHelpers_1 = require("../apiHelpers/transactionsApiHelpers"); const casting_1 = require("./casting"); const utils_1 = require("@mysten/sui/utils"); const cryptography_1 = require("@mysten/sui/cryptography"); const ed25519_1 = require("@mysten/sui/keypairs/ed25519"); const secp256k1_1 = require("@mysten/sui/keypairs/secp256k1"); const secp256r1_1 = require("@mysten/sui/keypairs/secp256r1"); /** * A utility class containing various helper functions for general use. */ class Helpers { 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; } static removeCircularReferences(obj, seen = new WeakSet()) { if (obj && typeof obj === "object") { if (seen.has(obj)) { return undefined; // Circular reference found, skip it } seen.add(obj); if (Array.isArray(obj)) { return obj.map((item) => this.removeCircularReferences(item, seen)); } else { const entries = Object.entries(obj).map(([key, value]) => [ key, this.removeCircularReferences(value, seen), ]); return Object.fromEntries(entries); } } return obj; } // ========================================================================= // Type Checking // ========================================================================= static isArrayOfStrings(value) { return (Array.isArray(value) && value.every((item) => typeof item === "string")); } // ========================================================================= // Sui Object Parsing // ========================================================================= static getObjectType(data) { var _b, _c; const objectType = (_b = data.data) === null || _b === void 0 ? void 0 : _b.type; // NOTE: should `Helpers.addLeadingZeroesToType` not be used here ? if (objectType) return Helpers.addLeadingZeroesToType(objectType); throw new Error("no object type found on " + ((_c = data.data) === null || _c === void 0 ? void 0 : _c.objectId)); } static getObjectId(data) { var _b, _c; const objectId = (_b = data.data) === null || _b === void 0 ? void 0 : _b.objectId; if (objectId) return Helpers.addLeadingZeroesToType(objectId); throw new Error("no object id found on " + ((_c = data.data) === null || _c === void 0 ? void 0 : _c.type)); } static getObjectFields(data) { var _b, _c; try { const content = (_b = data.data) === null || _b === void 0 ? void 0 : _b.content; return content.fields; } catch (e) { throw new Error("no object fields found on " + ((_c = data.data) === null || _c === void 0 ? void 0 : _c.objectId)); } } static getObjectDisplay(data) { var _b, _c; const display = (_b = data.data) === null || _b === void 0 ? void 0 : _b.display; if (display) return display; throw new Error("no object display found on " + ((_c = data.data) === null || _c === void 0 ? void 0 : _c.objectId)); } // ========================================================================= // Error Parsing // ========================================================================= static parseMoveErrorMessage(inputs) { const { errorMessage } = inputs; if (!errorMessage.toLowerCase().includes("moveabort")) return undefined; /* MoveAbort(MoveLocation { module: ModuleId { address: 8d8946c2a433e2bf795414498d9f7b32e04aca8dbf35a20257542dc51406242b, name: Identifier("orderbook") }, function: 11, instruction: 117, function_name: Some("fill_market_order") }, 3005) in command 2 */ const moveErrorCode = (inputs) => { const { errorMessage } = inputs; const startIndex = errorMessage.lastIndexOf(","); const endIndex = errorMessage.lastIndexOf(")"); if (startIndex <= 0 || endIndex <= 0 || startIndex >= endIndex) return undefined; try { const errorCode = parseInt(errorMessage.slice(startIndex + 1, endIndex)); if (Number.isNaN(errorCode)) return undefined; return errorCode; } catch (e) { return undefined; } }; const moveErrorPackageId = (inputs) => { const { errorMessage } = inputs; const startIndex = errorMessage.toLowerCase().indexOf("address:"); const endIndex = errorMessage.indexOf(", name:"); if (startIndex <= 0 || endIndex <= 0 || startIndex >= endIndex) return undefined; try { const packageId = Helpers.addLeadingZeroesToType("0x" + errorMessage .slice(startIndex + 8, endIndex) .trim() .replaceAll("0x", "")); if (!this.isValidHex(packageId)) return undefined; return packageId; } catch (e) { return undefined; } }; const moveErrorModule = (inputs) => { const { errorMessage } = inputs; const startIndex = errorMessage .toLowerCase() .indexOf('identifier("'); const endIndex = errorMessage.indexOf('")'); if (startIndex <= 0 || endIndex <= 0 || startIndex >= endIndex) return undefined; try { return errorMessage.slice(startIndex + 12, endIndex).trim(); } catch (e) { return undefined; } }; try { const errorCode = moveErrorCode({ errorMessage, }); const packageId = moveErrorPackageId({ errorMessage, }); const module = moveErrorModule({ errorMessage, }); if (errorCode === undefined || !packageId || !module) return undefined; return { errorCode, packageId, module, }; } catch (e) { return undefined; } } static translateMoveErrorMessage(inputs) { const { errorMessage, moveErrors } = inputs; const parsed = this.parseMoveErrorMessage({ errorMessage }); if (!parsed || !(parsed.packageId in moveErrors) || !(parsed.module in moveErrors[parsed.packageId]) || !(parsed.errorCode in moveErrors[parsed.packageId][parsed.module])) return undefined; return Object.assign(Object.assign({}, parsed), { error: moveErrors[parsed.packageId][parsed.module][parsed.errorCode] }); } } exports.Helpers = Helpers; _a = Helpers; // ========================================================================= // Api Helpers // ========================================================================= Helpers.dynamicFields = dynamicFieldsApiHelpers_1.DynamicFieldsApiHelpers; Helpers.events = eventsApiHelpers_1.EventsApiHelpers; Helpers.inspections = inspectionsApiHelpers_1.InspectionsApiHelpers; Helpers.objects = objectsApiHelpers_1.ObjectsApiHelpers; Helpers.transactions = transactionsApiHelpers_1.TransactionsApiHelpers; // ========================================================================= // Type Manipulation // ========================================================================= /** * Removes leading zeroes from the hexadecimal representation of a given object type. * @param type - The object type to strip leading zeroes from. * @returns The object type with leading zeroes removed from its hexadecimal representation. */ Helpers.stripLeadingZeroesFromType = (type) => type.replaceAll(/x0+/g, "x"); /** * Adds leading zeroes to a given `AnyObjectType` until it reaches a length of 64 characters. * If the input type already has a length greater than 64, an error is thrown. * @param type - The `AnyObjectType` to add leading zeroes to. * @returns The modified `AnyObjectType` with leading zeroes added. * @throws An error if the input type has a length greater than 64. */ Helpers.addLeadingZeroesToType = (type) => { // NOTE: is this safe to add ? // if (!Helpers.isValidType(type)) return 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 zeros = Array(EXPECTED_TYPE_LENGTH - typeLength) .fill("0") .reduce((acc, val) => acc + val, ""); const newType = "0x" + zeros + strippedType; return newType + typeSuffix; }; Helpers.splitNonSuiCoinType = (coin) => { const [uncastChain, coinType] = coin.split(":"); if (!uncastChain || !coinType) throw new Error("invalid coin type"); const chain = uncastChain; return { chain, coinType }; }; // ========================================================================= // Numbers // ========================================================================= Helpers.isNumber = (str) => /^\d*\.?\d*$/g.test(str); Helpers.sum = (arr) => arr.reduce((prev, cur) => prev + cur, 0); Helpers.sumBigInt = (arr) => arr.reduce((prev, cur) => prev + cur, BigInt(0)); Helpers.closeEnough = (a, b, tolerance) => Math.abs(a - b) <= tolerance * Math.max(a, b); Helpers.closeEnoughBigInt = (a, b, tolerance) => Helpers.closeEnough(Number(a), Number(b), tolerance); Helpers.veryCloseInt = (a, b, fixedOne) => Math.abs(Math.floor(a / fixedOne) - Math.floor(b / fixedOne)) <= 1; Helpers.blendedOperations = { mulNNN: (a, b) => a * b, mulNNB: (a, b) => BigInt(Math.floor(a * b)), mulNBN: (a, b) => a * Number(b), mulNBB: (a, b) => BigInt(Math.floor(a * Number(b))), mulBBN: (a, b) => Number(a * b), mulBBB: (a, b) => a * b, }; Helpers.maxBigInt = (...args) => args.reduce((m, e) => (e > m ? e : m)); Helpers.minBigInt = (...args) => args.reduce((m, e) => (e < m ? e : m)); Helpers.absBigInt = (num) => (num < BigInt(0) ? -num : num); // ========================================================================= // Display // ========================================================================= Helpers.capitalizeOnlyFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); // ========================================================================= // JSON // ========================================================================= Helpers.parseJsonWithBigint = (json, unsafeStringNumberConversion = false) => JSON.parse(json, (key, value) => { // handles bigint casting if (typeof value === "string" && /^-?\d+n$/.test(value)) { return BigInt(value.slice(0, -1)); } if (unsafeStringNumberConversion && typeof value === "string" && _a.isNumber(value)) { return BigInt(value); } return value; }); // ========================================================================= // General // ========================================================================= Helpers.deepCopy = (target) => { if (target === null) { return target; } if (target instanceof Date) { return new Date(target.getTime()); } if (target instanceof Array) { const cp = []; target.forEach((v) => { cp.push(v); }); return cp.map((n) => _a.deepCopy(n)); } if (typeof target === "object") { const cp = Object.assign({}, target); Object.keys(cp).forEach((k) => { cp[k] = _a.deepCopy(cp[k]); }); return cp; } return target; }; Helpers.indexOfMax = (arr) => { if (arr.length === 0) return -1; let max = arr[0]; let maxIndex = 0; for (let i = 1; i < arr.length; i++) { if (arr[i] > max) { maxIndex = i; max = arr[i]; } } return maxIndex; }; Helpers.uniqueArray = (arr) => [...new Set(arr)]; Helpers.sleep = (ms) => new Promise((r) => setTimeout(r, ms)); Helpers.createUid = () => Date.now().toString(36) + Math.random().toString(36).substring(2); Helpers.bifilter = (array, func) => { return array.reduce(([T, F], x, i, arr) => { if (func(x, i, arr) === false) return [T, [...F, x]]; else return [[...T, x], F]; }, [[], []]); }; Helpers.bifilterAsync = (array, func) => __awaiter(void 0, void 0, void 0, function* () { const predicates = yield Promise.all(array.map(func)); return _a.bifilter(array, (_, index) => predicates[index]); }); Helpers.filterObject = (obj, predicate) => Object.keys(obj).reduce((acc, key) => { const val = obj[key]; if (!predicate(key, val)) return acc; return Object.assign(Object.assign({}, acc), { [key]: val }); }, {}); Helpers.applySlippageBigInt = (amount, slippage) => { return (amount - BigInt(Math.floor(casting_1.Casting.normalizeSlippageTolerance(slippage) * Number(amount)))); }; Helpers.applySlippage = (amount, slippage) => { return amount - casting_1.Casting.normalizeSlippageTolerance(slippage) * amount; }; Helpers.isValidType = (str) => { // TODO: use regex const trimmedStr = str.trim(); return (trimmedStr.startsWith("0x") && trimmedStr.length >= 9 && trimmedStr.indexOf("::") >= 3 && trimmedStr.lastIndexOf("::") >= 6 && !trimmedStr.endsWith(":")); }; Helpers.isValidHex = (hexString) => { const hexPattern = /^(0x)?[0-9A-F]+$/i; return hexPattern.test(hexString); }; // ========================================================================= // Tx Command Input Construction // ========================================================================= // TODO: use this everywhere in api for tx command creation Helpers.addTxObject = (tx, object) => { return typeof object === "string" ? tx.object(object) : object; }; // ========================================================================= // Constructors // ========================================================================= // public static async createScallopProviders(inputs: { // network: SuiNetwork; // }): Promise<ScallopProviders> { // const network = inputs.network.toLowerCase(); // const networkType = // network === "local" // ? "localnet" // : network !== "mainnet" && // network !== "testnet" && // network !== "localnet" // ? undefined // : network; // if (!networkType) // throw new Error(`network \`${inputs.network}\` not found`); // const Main = new Scallop({ // networkType, // }); // const [Builder, Query] = await Promise.all([ // Main.createScallopBuilder(), // Main.createScallopQuery(), // ]); // // await Promise.all([Builder.init(), Query.init()]); // return { // Main, // Builder, // Query, // }; // } Helpers.isValidSuiAddress = (address) => (0, utils_1.isValidSuiAddress)((() => { if (!address.startsWith("0x") || address.length < 3) return ""; try { return Helpers.addLeadingZeroesToType(address); } catch (e) { return ""; } })()); // ========================================================================= // Keypair // ========================================================================= Helpers.keypairFromPrivateKey = (privateKey) => { const parsedKeypair = (0, cryptography_1.decodeSuiPrivateKey)(privateKey); return parsedKeypair.schema === "ED25519" ? ed25519_1.Ed25519Keypair.fromSecretKey(parsedKeypair.secretKey) : parsedKeypair.schema === "Secp256k1" ? secp256k1_1.Secp256k1Keypair.fromSecretKey(parsedKeypair.secretKey) : parsedKeypair.schema === "Secp256r1" ? secp256r1_1.Secp256r1Keypair.fromSecretKey(parsedKeypair.secretKey) : (() => { throw new Error(`unsupported schema \`${parsedKeypair.schema}\``); })(); };