client-aftermath-ts-sdk
Version:
Client Aftermath TypeScript SDK
430 lines (429 loc) • 18 kB
JavaScript
;
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}\``);
})();
};