wowok
Version:
Create, collaborate, and transact on your own terms with the AI-driven web3 collaboration protocol.
633 lines (632 loc) • 21.9 kB
JavaScript
import { BCS, getSuiMoveConfig, } from '@mysten/bcs';
import { ERROR, Errors } from './exception';
import { isValidSuiAddress, normalizeSuiAddress } from '@mysten/sui/utils';
import { RepositoryValueType, ValueType, Protocol } from './protocol';
export const MAX_U8 = BigInt('255');
export const MAX_U64 = BigInt('18446744073709551615');
export const MAX_U128 = BigInt('340282366920938463463374607431768211455');
export const MAX_U256 = BigInt('115792089237316195423570985008687907853269984665640564039457584007913129639935');
export const OPTION_NONE = 0;
export const ValueTypeConvert = (type) => {
if (type === ValueType.TYPE_U8 || type === ValueType.TYPE_U64 || type === ValueType.TYPE_U128 ||
type === ValueType.TYPE_U256) {
return RepositoryValueType.PositiveNumber;
}
else if (type === ValueType.TYPE_VEC_U8 || type === ValueType.TYPE_VEC_U64 || type === ValueType.TYPE_VEC_U128 ||
type === ValueType.TYPE_VEC_U256 || type === ValueType.TYPE_VEC_BOOL) {
return RepositoryValueType.PositiveNumber_Vec;
}
else if (type === ValueType.TYPE_ADDRESS) {
return RepositoryValueType.Address;
}
else if (type === ValueType.TYPE_VEC_ADDRESS) {
return RepositoryValueType.Address_Vec;
}
else if (type === ValueType.TYPE_STRING) {
return RepositoryValueType.String;
}
else if (type === ValueType.TYPE_VEC_STRING) {
return RepositoryValueType.String_Vec;
}
else if (type === ValueType.TYPE_BOOL) {
return RepositoryValueType.Bool;
}
return -1;
};
export const readOption = (arr, de) => {
let o = arr.splice(0, 1);
if (o[0] == 1) { // true
return { bNone: false, value: Bcs.getInstance().de(de, Uint8Array.from(arr)) };
}
else if (o[0] == 0) {
return { bNone: true, value: OPTION_NONE };
}
else {
ERROR(Errors.Fail, 'readOption: option invalid');
return { bNone: true, value: OPTION_NONE };
}
};
export const readOptionString = (arr) => {
let o = arr.splice(0, 1);
if (o[0] == 1) { // true
let r = ulebDecode(Uint8Array.from(arr));
let value = Bcs.getInstance().de(ValueType.TYPE_STRING, Uint8Array.from(arr));
arr.splice(0, r.value + r.length);
return { bNone: false, value: value };
}
else if (o[0] == 0) {
return { bNone: true, value: OPTION_NONE };
}
else {
ERROR(Errors.Fail, 'readOption: option invalid');
return { bNone: true, value: OPTION_NONE };
}
};
export const ulebDecode = (arr) => {
let total = 0;
let shift = 0;
let len = 0;
// eslint-disable-next-line no-constant-condition
while (true) {
let byte = arr[len];
len += 1;
total |= (byte & 0x7f) << shift;
if ((byte & 0x80) === 0) {
break;
}
shift += 7;
}
return {
value: total,
length: len,
};
};
export const readVec = (arr, cb) => {
let r = ulebDecode(Uint8Array.from(arr));
arr.splice(0, r.length);
let result = [];
for (let i = 0; i < r.value; i++) {
result.push(cb(arr, i, r.value));
}
return result;
};
export const cb_U8 = (arr, i, length) => {
return arr.shift();
};
export const cb_U64 = (arr, i, length) => {
return arr.splice(0, 8);
};
export const cb_U128 = (arr, i, length) => {
return arr.splice(0, 16);
};
export const cb_U256 = (arr, i, length) => {
return arr.splice(0, 32);
};
export const concatenate = (resultConstructor, ...arrays) => {
let totalLength = 0;
for (const arr of arrays) {
totalLength += arr.length;
}
const result = new resultConstructor(totalLength);
let offset = 0;
for (const arr of arrays) {
result.set(arr, offset);
offset += arr.length;
}
return result;
};
export const parseObjectType = (chain_type, header = 'payment::Payment<') => {
if (chain_type) {
const i = chain_type.indexOf(header);
if (i > 0) {
let r = chain_type.slice(i + header.length, chain_type.length - 1);
return r;
}
}
return '';
};
export const array_equal = (arr1, arr2) => {
if (arr1.length !== arr2.length) {
return false;
}
return !arr1.some((item) => !arr2.includes(item));
};
export const array_unique = (arr) => {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (newArr.indexOf(arr[i]) == -1) {
newArr.push(arr[i]);
}
}
return newArr;
};
export function capitalize(s) {
return s && s[0].toUpperCase() + s.slice(1);
}
// for: "0xsdjfkskf<0x2::sui::coin<xxx>, 0xfdfff<>>"
export function parse_object_type(object_data) {
var object_type = [];
let type_pos = object_data.indexOf('<');
if (type_pos >= 0) {
let t = object_data.slice((type_pos + 1), object_data.length - 1);
object_type = t.split(',');
}
return object_type;
}
export class Bcs {
bcs = new BCS(getSuiMoveConfig());
static _instance;
constructor() {
this.bcs.registerEnumType('Option<T>', {
'none': null,
'some': 'T',
});
this.bcs.registerStructType('EntStruct', {
'avatar': 'vector<u8>',
'resource': "Option<address>",
"safer_name": "vector<string>",
"safer_value": "vector<string>",
'like': BCS.U32,
'dislike': BCS.U32,
});
this.bcs.registerStructType('TagStruct', {
'nick': 'string',
'tags': "vector<string>",
});
this.bcs.registerStructType('PersonalInfo', {
'name': 'vector<u8>',
'description': 'vector<u8>',
'avatar': BCS.STRING,
'twitter': BCS.STRING,
'discord': BCS.STRING,
'homepage': BCS.STRING,
});
this.bcs.registerStructType('OptionAddress', {
'address': 'Option<address>',
});
this.bcs.registerStructType('Guards', {
'guards': 'vector<OptionAddress>',
});
this.bcs.registerStructType('Perm', {
'index': BCS.U64,
'guard': 'Option<address>'
});
this.bcs.registerStructType('Perms', {
'perms': 'vector<Perm>'
});
}
static getInstance() {
if (!Bcs._instance) {
Bcs._instance = new Bcs();
}
;
return Bcs._instance;
}
ser_option_u32(data) {
return this.bcs.ser('Option<u32>', { 'some': data }).toBytes();
}
ser(type, data) {
if (typeof (type) === 'string') {
return this.bcs.ser(type, data).toBytes();
}
switch (type) {
case ValueType.TYPE_BOOL:
return this.bcs.ser(BCS.BOOL, data).toBytes();
case ValueType.TYPE_ADDRESS:
return this.bcs.ser(BCS.ADDRESS, data).toBytes();
case ValueType.TYPE_U64:
return this.bcs.ser(BCS.U64, data).toBytes();
case ValueType.TYPE_U8:
return this.bcs.ser(BCS.U8, data).toBytes();
case ValueType.TYPE_VEC_U8:
return this.bcs.ser('vector<u8>', data).toBytes();
case ValueType.TYPE_U128:
return this.bcs.ser(BCS.U128, data).toBytes();
case ValueType.TYPE_VEC_ADDRESS:
return this.bcs.ser('vector<address>', data).toBytes();
case ValueType.TYPE_VEC_BOOL:
return this.bcs.ser('vector<bool>', data).toBytes();
case ValueType.TYPE_VEC_VEC_U8:
return this.bcs.ser('vector<vector<u8>>', data).toBytes();
case ValueType.TYPE_VEC_U64:
return this.bcs.ser('vector<u64>', data).toBytes();
case ValueType.TYPE_VEC_U128:
return this.bcs.ser('vector<u128>', data).toBytes();
case ValueType.TYPE_OPTION_ADDRESS:
return this.bcs.ser('Option<address>', { 'some': data }).toBytes();
case ValueType.TYPE_OPTION_BOOL:
return this.bcs.ser('Option<bool>', { 'some': data }).toBytes();
case ValueType.TYPE_OPTION_U8:
return this.bcs.ser('Option<u8>', { 'some': data }).toBytes();
case ValueType.TYPE_OPTION_U64:
return this.bcs.ser('Option<u64>', { 'some': data }).toBytes();
case ValueType.TYPE_OPTION_U128:
return this.bcs.ser('Option<u128>', { 'some': data }).toBytes();
case ValueType.TYPE_OPTION_U256:
return this.bcs.ser('Option<u256>', { 'some': data }).toBytes();
case ValueType.TYPE_OPTION_STRING:
return this.bcs.ser('Option<string>', { 'some': data }).toBytes();
case ValueType.TYPE_VEC_U256:
return this.bcs.ser('vector<u256>', data).toBytes();
case ValueType.TYPE_U256:
return this.bcs.ser(BCS.U256, data).toBytes();
case ValueType.TYPE_STRING:
const d = new TextEncoder().encode(data);
return this.bcs.ser('vector<u8>', d).toBytes();
case ValueType.TYPE_VEC_STRING:
return this.bcs.ser('vector<vector<u8>>', data.map((v) => { return new TextEncoder().encode(v); })).toBytes();
default:
ERROR(Errors.bcsTypeInvalid, 'ser');
}
return new Uint8Array();
}
de(type, data) {
if (typeof (type) === 'string') {
return this.bcs.de(type, data);
}
switch (type) {
case ValueType.TYPE_BOOL:
return this.bcs.de(BCS.BOOL, data);
case ValueType.TYPE_ADDRESS:
return this.bcs.de(BCS.ADDRESS, data);
case ValueType.TYPE_U64:
return this.bcs.de(BCS.U64, data);
case ValueType.TYPE_U8:
return this.bcs.de(BCS.U8, data);
case ValueType.TYPE_VEC_U8:
return this.bcs.de('vector<u8>', data);
case ValueType.TYPE_U128:
return this.bcs.de(BCS.U128, data);
case ValueType.TYPE_VEC_ADDRESS:
return this.bcs.de('vector<address>', data);
case ValueType.TYPE_VEC_BOOL:
return this.bcs.de('vector<bool>', data);
case ValueType.TYPE_VEC_VEC_U8:
return this.bcs.de('vector<vector<u8>>', data);
case ValueType.TYPE_VEC_U64:
return this.bcs.de('vector<u64>', data);
case ValueType.TYPE_VEC_U128:
return this.bcs.de('vector<u128>', data);
case ValueType.TYPE_OPTION_ADDRESS:
return this.bcs.de('Option<address>', data);
case ValueType.TYPE_OPTION_BOOL:
return this.bcs.de('Option<bool>', data);
case ValueType.TYPE_OPTION_U8:
return this.bcs.de('Option<u8>', data);
case ValueType.TYPE_OPTION_U64:
return this.bcs.de('Option<u64>', data);
case ValueType.TYPE_OPTION_U128:
return this.bcs.de('Option<u128>', data);
case ValueType.TYPE_OPTION_U256:
return this.bcs.de('Option<u256>', data);
case ValueType.TYPE_OPTION_STRING:
return this.bcs.de('Option<string>', data);
case ValueType.TYPE_VEC_U256:
return this.bcs.de('vector<u256>', data);
case ValueType.TYPE_STRING:
const r = new TextDecoder().decode(Uint8Array.from(this.bcs.de('vector<u8>', data)));
return r;
case ValueType.TYPE_VEC_STRING:
return this.bcs.de('vector<string>', data);
case ValueType.TYPE_U256:
return this.bcs.de(BCS.U256, data);
default:
ERROR(Errors.bcsTypeInvalid, 'de');
}
}
de_ent(data) {
if (!data || data.length < 2)
return '';
const struct_vec = this.bcs.de('vector<u8>', data);
return this.bcs.de('EntStruct', Uint8Array.from(struct_vec));
}
de_entInfo(data) {
if (!data || data.length === 0)
return undefined;
let r = this.bcs.de('PersonalInfo', data);
r.name = new TextDecoder().decode(Uint8Array.from(r.name));
r.description = new TextDecoder().decode(Uint8Array.from(r.description));
return r;
}
de_tags(data) {
if (!data || data.length === 0)
return '';
const struct_vec = this.bcs.de('vector<u8>', data);
return this.bcs.de('TagStruct', Uint8Array.from(struct_vec));
}
de_perms(data) {
if (!data || data.length < 1)
return '';
let r = this.bcs.de('Perms', data);
return r.perms.map((v) => {
return { index: v?.index, guard: v?.guard?.none ? undefined : '0x' + v?.guard?.some };
});
}
}
export function stringToUint8Array(str) {
const encoder = new TextEncoder();
const view = encoder.encode(str);
return new Uint8Array(view.buffer);
}
export function numToUint8Array(num) {
if (!num)
return new Uint8Array(0);
const a = [];
a.unshift(num & 255);
while (num >= 256) {
num = num >>> 8;
a.unshift(num & 255);
}
return new Uint8Array(a);
}
export const isArr = (origin) => {
let str = '[object Array]';
return Object.prototype.toString.call(origin) == str ? true : false;
};
export const deepClone = (origin, target) => {
let tar = target || {};
for (const key in origin) {
if (Object.prototype.hasOwnProperty.call(origin, key)) {
if (typeof origin[key] === 'object' && origin[key] !== null) {
tar[key] = isArr(origin[key]) ? [] : {};
deepClone(origin[key], tar[key]);
}
else {
tar[key] = origin[key];
}
}
}
return tar;
};
export const MAX_DESCRIPTION_LENGTH = 4000;
export const MAX_NAME_LENGTH = 64;
export const MAX_ENDPOINT_LENGTH = 1024;
// export const OptionNone = (txb:TransactionBlock) : TransactionArgument => { return txb.pure([], BCS.U8) };
const IsValidStringLength = (str, max_len) => {
return Bcs.getInstance().ser(ValueType.TYPE_STRING, str).length <= max_len;
};
export const IsValidDesription = (description) => {
return IsValidStringLength(description, MAX_DESCRIPTION_LENGTH);
};
export const IsValidName = (name) => {
if (!name || name.length === 0) {
return false;
}
return IsValidStringLength(name, MAX_NAME_LENGTH);
};
export const IsValidName_AllowEmpty = (name) => { return IsValidStringLength(name, MAX_NAME_LENGTH); };
export const IsValidEndpoint = (endpoint) => {
return (endpoint.length > 0 && endpoint.length <= MAX_ENDPOINT_LENGTH && isValidHttpUrl(endpoint));
};
export const IsValidAddress = (addr) => {
if (!addr || !isValidSuiAddress(addr)) {
return false;
}
return true;
};
export const IsValidCoinType = (coin_type) => {
if (!coin_type) {
return false;
}
return coin_type.startsWith('0x2::coin::Coin') || coin_type.startsWith('0x0000000000000000000000000000000000000000000000000000000000000002');
};
export const getUTCDayStartByDivision = (interval = 86400000) => {
const now = Date.now();
return Math.floor(now / interval) * interval;
};
export const IsValidBigint = (value, max = MAX_U256, min) => {
if (value === '' || value === undefined)
return false;
try {
const v = BigInt(value);
if (v <= max) {
if (min !== undefined) {
return v >= min;
}
return true;
}
}
catch (e) {
}
;
return false;
};
export const IsValidU8 = (value, min = 0) => {
return IsValidBigint(value, MAX_U8, BigInt(min));
};
export const IsValidU64 = (value, min = 0) => {
return IsValidBigint(value, MAX_U64, BigInt(min));
};
export const IsValidU128 = (value, min = 0) => {
return IsValidBigint(value, MAX_U128, BigInt(min));
};
export const IsValidU256 = (value, min = 0) => {
return IsValidBigint(value, MAX_U256, BigInt(min));
};
export const IsValidTokenType = (argType) => {
if (!argType || argType.length === 0) {
return false;
}
let arr = argType.split('::');
if (arr.length !== 3) {
return false;
}
if ((!IsValidAddress(arr[0]) && arr[0] != '0x2') || arr[1].length === 0 || arr[2].length === 0) {
return false;
}
return true;
};
export const IsValidArgType = (argType) => {
if (!argType || argType.length === 0) {
return false;
}
let arr = argType.split('::');
if (arr.length < 3) {
return false;
}
return true;
};
export const IsValidInt = (value) => {
if (typeof (value) === 'string') {
value = parseInt(value);
}
return Number.isSafeInteger(value);
};
export const IsValidPercent = (value) => {
return IsValidBigint(value, BigInt(100), BigInt(0));
};
export const IsValidArray = (arr, validFunc) => {
for (let i = 0; i < arr.length; i++) {
if (!validFunc(arr[i])) {
return false;
}
}
return true;
};
export const ResolveU64 = (value) => {
const max = MAX_U64;
if (value > max) {
return max;
}
else {
return value;
}
};
function removeTrailingZeros(numberString) {
const trimmedString = numberString.trim();
const decimalIndex = trimmedString.indexOf('.');
if (decimalIndex !== -1) {
let endIndex = trimmedString.length - 1;
while (trimmedString[endIndex] === '0') {
endIndex--;
}
if (trimmedString[endIndex] === '.') {
endIndex--;
}
return trimmedString.slice(0, endIndex + 1);
}
return trimmedString;
}
export const ResolveBalance = (balance, decimals) => {
if (!balance)
return '';
if (balance === '0')
return '0';
if (decimals <= 0)
return balance;
var pos = decimals - balance.length;
if (pos === 0) {
return removeTrailingZeros('.' + (balance));
}
else if (pos < 0) {
let start = balance.slice(0, Math.abs(pos));
let end = balance.slice(Math.abs(pos));
return removeTrailingZeros(start + '.' + end);
}
else {
return removeTrailingZeros('.' + balance.padStart(decimals, '0'));
}
};
export const ParseType = (type) => {
if (type) {
const COIN = '0x2::coin::Coin<';
let i = type.indexOf(COIN);
if (i >= 0) {
let coin = type.slice(i + COIN.length, type.length - 1);
if (coin.indexOf('<') === -1) {
while (coin[coin.length - 1] == '>') {
coin = coin.slice(0, -1);
}
;
let t = coin.lastIndexOf('::');
return { isCoin: true, coin: coin, token: coin.slice(t + 2) };
}
}
}
return { isCoin: false, coin: '', token: '' };
};
export function insertAtHead(array, value) {
const newLength = array.length + 1;
const newArray = new Uint8Array(newLength);
newArray.set([value], 0);
newArray.set(array, 1);
return newArray;
}
export function toFixed(x) {
let res = '';
if (Math.abs(x) < 1.0) {
var e = parseInt(x.toString().split('e-')[1]);
if (e) {
x *= Math.pow(10, e - 1);
res = '0.' + (new Array(e)).join('0') + x.toString().substring(2);
}
}
else {
var e = parseInt(x.toString().split('+')[1]);
if (e > 20) {
e -= 20;
x /= Math.pow(10, e);
res = x + (new Array(e + 1)).join('0');
}
}
return res;
}
export function isValidHttpUrl(url) {
let r;
try {
r = new URL(url);
}
catch (_) {
return false;
}
return r.protocol === "http:" || r.protocol === "https:" || r.protocol === 'ipfs:';
}
export const uint2address = (value) => {
return normalizeSuiAddress(value.toString(16));
};
export const query_object = (param) => {
if (param.id) {
if (param?.onBegin)
param.onBegin(param.id);
Protocol.Client().getObject({ id: param.id, options: { showContent: true, showType: true, showOwner: true } }).then((res) => {
if (res.error) {
if (param?.onObjectErr)
param.onObjectErr(param.id, res.error);
}
else {
if (param?.onObjectRes)
param.onObjectRes(param.id, res);
}
}).catch((err) => {
console.log(err);
if (param?.onObjectErr)
param.onObjectErr(param.id, err);
});
Protocol.Client().getDynamicFields({ parentId: param.id }).then((res) => {
if (param?.onDynamicRes)
param.onDynamicRes(param.id, res);
if (res.data.length > 0) {
Protocol.Client().multiGetObjects({ ids: res.data.map(v => v.objectId), options: { showContent: true } }).then((fields) => {
if (param?.onFieldsRes)
param.onFieldsRes(param.id, fields);
}).catch((err) => {
console.log(err);
if (param?.onFieldsErr)
param.onFieldsErr(param.id, err);
});
}
}).catch((err) => {
console.log(err);
if (param?.onDynamicErr)
param.onDynamicErr(param.id, err);
});
}
};
export const FirstLetterUppercase = (str) => {
if (!str)
return '';
return str.substring(0, 1).toUpperCase() + str.substring(1);
};
export function hasDuplicates(array) {
return array.some((item, index) => array.findIndex(i => i === item) !== index);
}