blub-sdk
Version:
A modular SDK for interacting with the BLUB ecosystem on the Sui blockchain.
174 lines (153 loc) • 4.4 kB
text/typescript
import { normalizeSuiObjectId } from "@mysten/sui/utils";
import {
GAS_TYPE_ARG,
GAS_TYPE_ARG_LONG,
SuiAddress,
SuiStructTag,
} from "./sui";
import { CoinUtils } from "./CoinAssist";
const EQUAL = 0;
const LESS_THAN = 1;
const GREATER_THAN = 2;
function cmp(a: number, b: number) {
if (a === b) {
return EQUAL;
}
if (a < b) {
return LESS_THAN;
}
return GREATER_THAN;
}
function compare(symbolX: string, symbolY: string) {
let i = 0;
const len =
symbolX.length <= symbolY.length ? symbolX.length : symbolY.length;
const lenCmp = cmp(symbolX.length, symbolY.length);
while (i < len) {
const elemCmp = cmp(symbolX.charCodeAt(i), symbolY.charCodeAt(i));
i += 1;
if (elemCmp !== 0) {
return elemCmp;
}
}
return lenCmp;
}
export function isSortedSymbols(symbolX: string, symbolY: string) {
return compare(symbolX, symbolY) === LESS_THAN;
}
export function composeType(
address: string,
generics: SuiAddress[]
): SuiAddress;
export function composeType(
address: string,
struct: string,
generics?: SuiAddress[]
): SuiAddress;
export function composeType(
address: string,
module: string,
struct: string,
generics?: SuiAddress[]
): SuiAddress;
export function composeType(address: string, ...args: unknown[]): SuiAddress {
const generics: string[] = Array.isArray(args[args.length - 1])
? (args.pop() as string[])
: [];
const chains = [address, ...args].filter(Boolean);
let result: string = chains.join("::");
if (generics && generics.length) {
result += `<${generics.join(", ")}>`;
}
return result;
}
export function extractAddressFromType(type: string) {
return type.split("::")[0];
}
export function extractStructTagFromType(type: string): SuiStructTag {
try {
let _type = type.replace(/\s/g, "");
const genericsString = _type.match(/(<.+>)$/);
const generics = genericsString?.[0]?.match(
/(\w+::\w+::\w+)(?:<.*?>(?!>))?/g
);
if (generics) {
_type = _type.slice(0, _type.indexOf("<"));
const tag = extractStructTagFromType(_type);
const structTag: SuiStructTag = {
...tag,
type_arguments: generics.map(
(item) => extractStructTagFromType(item).source_address
),
};
structTag.type_arguments = structTag.type_arguments.map((item) => {
return CoinUtils.isSuiCoin(item)
? item
: extractStructTagFromType(item).source_address;
});
structTag.source_address = composeType(
structTag.full_address,
structTag.type_arguments
);
return structTag;
}
const parts = _type.split("::");
const isSuiCoin = _type === GAS_TYPE_ARG || _type === GAS_TYPE_ARG_LONG;
const structTag: SuiStructTag = {
full_address: _type,
address: isSuiCoin ? "0x2" : normalizeSuiObjectId(parts[0]),
module: parts[1],
name: parts[2],
type_arguments: [],
source_address: "",
};
structTag.full_address = `${structTag.address}::${structTag.module}::${structTag.name}`;
structTag.source_address = composeType(
structTag.full_address,
structTag.type_arguments
);
return structTag;
} catch {
return {
full_address: type,
address: "",
module: "",
name: "",
type_arguments: [],
source_address: type,
};
}
}
export function normalizeCoinType(coinType: string): string {
return extractStructTagFromType(coinType).source_address;
}
export function fixSuiObjectId(value: string): string {
if (value.toLowerCase().startsWith("0x")) {
return normalizeSuiObjectId(value);
}
return value;
}
/**
* Recursively traverses the given data object and patches any string values that represent Sui object IDs.
*
* @param {any} data - The data object to be patched.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function patchFixSuiObjectId(data: any) {
for (const key in data) {
const type = typeof data[key];
if (type === "object") {
patchFixSuiObjectId(data[key]);
} else if (type === "string") {
const value = data[key];
data[key] = fixSuiObjectId(value);
}
}
}
export function createTarget(
packageName: string,
moduleName: string,
functionName: string
): `${string}::${string}::${string}` {
return `${packageName}::${moduleName}::${functionName}`;
}