@unique-nft/api
Version:
Definitely typed JS API for the Unique Network blockchain
2,640 lines • 95.6 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to2, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to2, key) && key !== except)
__defProp(to2, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to2;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
AttributeType: () => AttributeType,
AttributeTypeValues: () => AttributeTypeValues,
COLLECTION_SCHEMA_NAME: () => COLLECTION_SCHEMA_NAME,
Ethereum: () => Ethereum,
IntegerAttributeTypes: () => IntegerAttributeTypes,
NumberAttributeTypes: () => NumberAttributeTypes,
SchemaTools: () => SchemaTools,
StringAttributeTypes: () => StringAttributeTypes,
Substrate: () => Substrate,
URL_TEMPLATE_INFIX: () => URL_TEMPLATE_INFIX,
UniqueUtils: () => UniqueUtils,
WS_RPC: () => WS_RPC,
coins: () => coin_exports,
constants: () => constants_exports,
init: () => init2,
libs: () => libs_exports
});
module.exports = __toCommonJS(src_exports);
var import_augment_api = require("@unique-nft/unique-mainnet-types/augment-api");
// src/libs.ts
var libs_exports = {};
__export(libs_exports, {
getEthers: () => getEthers,
getPolkadotApi: () => getPolkadotApi,
getPolkadotExtensionDapp: () => getPolkadotExtensionDapp,
getPolkadotKeyring: () => getPolkadotKeyring,
getPolkadotUtilCrypto: () => getPolkadotUtilCrypto,
init: () => init,
rpcDefinitions: () => rpcDefinitions
});
var import_definitions = require("@unique-nft/opal-testnet-types/definitions");
var import_definitions2 = require("@unique-nft/quartz-mainnet-types/definitions");
var import_definitions3 = require("@unique-nft/unique-mainnet-types/definitions");
// src/tsUtils.ts
var getKeys = (o) => Object.keys(o);
var getValues = (o) => Object.values(o);
var getEntries = (o) => Object.entries(o);
var getEnumValues = (en) => {
const arr = getValues(en);
return arr.slice(arr.length / 2);
};
var safeJSONParse = (str) => {
try {
return JSON.parse(str);
} catch {
return str;
}
};
// src/libs.ts
var rpcDefinitions = {
opal: import_definitions.unique.rpc,
quartz: import_definitions2.unique.rpc,
unique: import_definitions3.unique.rpc
};
var libs = {
ethers: null,
api: null,
keyring: null,
utilCrypto: null,
extensionDapp: null
};
var defaultInitOptions = {};
async function init(options = defaultInitOptions) {
const inBrowser = typeof window !== "undefined";
const libRequest = options.initLibs;
const tmpLibs = getKeys(libs).reduce((acc, key) => {
acc[key] = null;
return acc;
}, {});
[
tmpLibs.ethers,
tmpLibs.api,
tmpLibs.keyring,
tmpLibs.utilCrypto,
tmpLibs.extensionDapp
] = await Promise.all([
import("ethers"),
libRequest && !libRequest?.api ? null : import("@polkadot/api"),
libRequest && !libRequest?.keyring ? null : import("@polkadot/keyring"),
libRequest && !libRequest?.utilCrypto ? null : import("@polkadot/util-crypto"),
!inBrowser || libRequest && !libRequest?.extensionDapp ? null : import("@polkadot/extension-dapp")
]);
for (const key of getKeys(tmpLibs)) {
if (tmpLibs[key])
libs[key] = tmpLibs[key];
}
if (libs.extensionDapp && options.connectToPolkadotExtensionsAs && libs.extensionDapp.isWeb3Injected) {
await libs.extensionDapp.web3Enable(options.connectToPolkadotExtensionsAs);
}
}
var checkModuleExists = (moduleVar, moduleName) => {
if (!moduleVar) {
throw new Error(`No ${moduleName} found. Please call \`init()\` first.`);
}
return moduleVar;
};
function getPolkadotApi() {
return checkModuleExists(libs.api, `@polkadot/api`);
}
function getEthers() {
return checkModuleExists(libs.ethers, `ethers`);
}
function getPolkadotKeyring() {
return checkModuleExists(libs.keyring, `@polkadot/keyring`);
}
function getPolkadotUtilCrypto() {
return checkModuleExists(libs.utilCrypto, `@polkadot/util-crypto`);
}
function getPolkadotExtensionDapp() {
return checkModuleExists(libs.extensionDapp, `@polkadot/extension-dapp`);
}
// src/constants.ts
var constants_exports = {};
__export(constants_exports, {
COLLECTION_ADDRESS_PREFIX: () => COLLECTION_ADDRESS_PREFIX,
NESTING_PREFIX: () => NESTING_PREFIX,
WS_RPC: () => WS_RPC
});
var NESTING_PREFIX = "0xf8238ccfff8ed887463fd5e0";
var COLLECTION_ADDRESS_PREFIX = "0x17c4e6453cc49aaaaeaca894e6d9683e";
var WS_RPC = {
unique: "wss://eu-ws.unique.network",
quartz: "wss://quartz.unique.network",
uniqueRC: "wss://ws-rc.unique.network",
opal: "wss://opal.unique.network",
polkadot: "wss://rpc.polkadot.io",
kusama: "wss://quartz.api.onfinality.io/public-ws"
};
// src/utils/address/index.ts
var address_exports = {};
__export(address_exports, {
Address: () => Address,
StringUtils: () => stringUtils_exports,
algorithms: () => imports_exports,
collection: () => collection,
compare: () => compare,
constants: () => constants_exports2,
extract: () => extract,
is: () => is,
mirror: () => mirror,
nesting: () => nesting,
normalize: () => normalize,
substrate: () => substrate,
to: () => to,
validate: () => validate
});
// src/utils/address/constants.ts
var constants_exports2 = {};
__export(constants_exports2, {
COLLECTION_ADDRESS_PREFIX: () => COLLECTION_ADDRESS_PREFIX2,
NESTING_PREFIX: () => NESTING_PREFIX2,
STATIC_ADDRESSES: () => STATIC_ADDRESSES
});
var STATIC_ADDRESSES = {
contractHelpers: "0x842899ECF380553E8a4de75bF534cdf6fBF64049",
collectionHelpers: "0x6C4E9fE1AE37a41E93CEE429e8E1881aBdcbb54F"
};
var NESTING_PREFIX2 = "0xf8238ccfff8ed887463fd5e0";
var COLLECTION_ADDRESS_PREFIX2 = "0x17c4e6453cc49aaaaeaca894e6d9683e";
// src/utils/address/imports.ts
var imports_exports = {};
__export(imports_exports, {
base58: () => base58,
base64: () => base64,
basex: () => import_base_x.default,
blake2b: () => import_blake2b.blake2b,
keccak_256: () => import_sha3.keccak_256
});
var import_base_x = __toESM(require("base-x"));
var import_sha3 = require("@noble/hashes/sha3");
var import_blake2b = require("@noble/hashes/blake2b");
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var base58 = (0, import_base_x.default)(BASE58_ALPHABET);
var base64 = (0, import_base_x.default)(BASE64_ALPHABET);
// src/utils/address/stringUtils.ts
var stringUtils_exports = {};
__export(stringUtils_exports, {
DWORDHexString: () => DWORDHexString,
hexStringToString: () => hexStringToString,
hexToU8a: () => hexToU8a,
parseAndCheckTheNumberIsDWORD: () => parseAndCheckTheNumberIsDWORD,
safeJsonParseStringOrHexString: () => safeJsonParseStringOrHexString,
str2vec: () => str2vec,
strToU8a: () => strToU8a,
u8aToHex: () => u8aToHex,
vec2str: () => vec2str
});
var vec2str = (arr) => {
return arr.map((x) => String.fromCharCode(typeof x === "number" ? x : parseInt(x, 10))).join("");
};
var str2vec = (str) => {
if (typeof str !== "string") {
return str;
}
return str.split("").map((x) => x.charCodeAt(0));
};
var strToU8a = (str) => new Uint8Array(str2vec(str));
var hexToU8a = (hexString) => Uint8Array.from(((hexString.startsWith("0x") ? hexString.slice(2) : hexString).match(/.{1,2}/g) || []).map((byte) => parseInt(byte, 16)));
var u8aToHex = (bytes) => {
const arr = bytes instanceof Uint8Array ? Array.from(bytes) : bytes;
return "0x" + arr.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
};
var hexStringToString = (hexString) => ((hexString.startsWith("0x") ? hexString.slice(2) : hexString).match(/.{1,2}/g) || []).map((el) => String.fromCharCode(parseInt(el, 16))).join("");
var safeJsonParseStringOrHexString = (stringOrHexString) => {
try {
return JSON.parse(stringOrHexString);
} catch {
return safeJSONParse(hexStringToString(stringOrHexString));
}
};
var parseAndCheckTheNumberIsDWORD = (n) => {
const num = typeof n === "string" ? parseInt(n, 10) : n;
if (isNaN(num))
throw new Error(`Passed number is NaN: ${n}`);
if (num < 0)
throw new Error(`Passed number is less than 0: ${n}`);
if (num > 4294967295)
throw new Error(`Passed number is more than 2**32: ${n}`);
return num;
};
var DWORDHexString = {
fromNumber: (n) => {
return parseAndCheckTheNumberIsDWORD(n).toString(16).padStart(8, "0");
},
toNumber: (s) => {
const num = parseInt(s, 16);
if (isNaN(num))
throw new Error(`Passed string is not hexadecimal: ${s}`);
return num;
}
};
// src/utils/address/ethereum.ts
var unsafeNormalizeEthereumAddress = (address) => {
const addr = address.toLowerCase().replace(/^0x/i, "");
const addressHash = u8aToHex((0, import_sha3.keccak_256)(addr)).replace(/^0x/i, "");
let checksumAddress = "0x";
for (let i = 0; i < addr.length; i++) {
checksumAddress += parseInt(addressHash[i], 16) > 7 ? addr[i].toUpperCase() : addr[i];
}
return checksumAddress;
};
var normalizeEthereumAddress = (address) => {
validate.ethereumAddress(address);
return unsafeNormalizeEthereumAddress(address);
};
var compareEthereumAddresses = (address1, address2) => {
const addr1 = typeof address1 === "string" ? address1 : address1.Ethereum || address1.ethereum;
const addr2 = typeof address2 === "string" ? address2 : address2.Ethereum || address2.ethereum;
if (!addr1 || !addr2 || !is.ethereumAddress(addr1) || !is.ethereumAddress(addr2)) {
return false;
}
return addr1.toLowerCase() === addr2.toLowerCase();
};
var collectionIdToEthAddress = (collectionId) => {
validate.collectionId(collectionId);
return unsafeNormalizeEthereumAddress(COLLECTION_ADDRESS_PREFIX2 + DWORDHexString.fromNumber(collectionId));
};
var ethAddressToCollectionId = (address) => {
validate.collectionAddress(address);
return DWORDHexString.toNumber(address.slice(-8));
};
var collectionIdAndTokenIdToNestingAddress = (collectionId, tokenId) => {
validate.collectionId(collectionId);
validate.tokenId(tokenId);
return unsafeNormalizeEthereumAddress(NESTING_PREFIX2 + DWORDHexString.fromNumber(collectionId) + DWORDHexString.fromNumber(tokenId));
};
var nestingAddressToCollectionIdAndTokenId = (address) => {
validate.nestingAddress(address);
return {
collectionId: DWORDHexString.toNumber(address.slice(-16, -8)),
tokenId: DWORDHexString.toNumber(address.slice(-8))
};
};
// src/utils/address/substrate.ts
var blake2AsU8a = (u8a, dkLen = 32) => {
return (0, import_blake2b.blake2b)(u8a, { dkLen });
};
var u8aConcat = (u8as) => {
let offset = 0;
let length = 0;
for (let i = 0; i < u8as.length; i++) {
length += u8as[i].length;
}
const result = new Uint8Array(length);
for (let i = 0; i < u8as.length; i++) {
result.set(u8as[i], offset);
offset += u8as[i].length;
}
return result;
};
var SS58_PREFIX = new Uint8Array([83, 83, 53, 56, 80, 82, 69]);
var sshash = (data) => {
return blake2AsU8a(u8aConcat([SS58_PREFIX, data]), 64);
};
var checkAddressChecksum = (decoded) => {
const ss58Length = decoded[0] & 64 ? 2 : 1;
const ss58Decoded = ss58Length === 1 ? decoded[0] : (decoded[0] & 63) << 2 | decoded[1] >> 6 | (decoded[1] & 63) << 8;
const isPublicKey = [34 + ss58Length, 35 + ss58Length].includes(decoded.length);
const length = decoded.length - (isPublicKey ? 2 : 1);
const hash = sshash(decoded.subarray(0, length));
const isValid = (decoded[0] & 128) === 0 && ![46, 47].includes(decoded[0]) && (isPublicKey ? decoded[decoded.length - 2] === hash[0] && decoded[decoded.length - 1] === hash[1] : decoded[decoded.length - 1] === hash[0]);
return [isValid, length, ss58Length, ss58Decoded];
};
var normalizeSubstrateAddress = (address, prefix = 42) => {
return encodeSubstrateAddress(decodeSubstrateAddress(address).u8a, prefix);
};
function encodeSubstrateAddress(key, ss58Format = 42) {
const u8a = typeof key === "string" ? hexToU8a(key) : typeof key === "bigint" ? hexToU8a(key.toString(16)) : key;
if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {
throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);
}
const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];
if (!allowedDecodedLengths.includes(u8a.length)) {
throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(", ")}`);
}
const u8aPrefix = ss58Format < 64 ? new Uint8Array([ss58Format]) : new Uint8Array([
(ss58Format & 252) >> 2 | 64,
ss58Format >> 8 | (ss58Format & 3) << 6
]);
const input = u8aConcat([u8aPrefix, u8a]);
return base58.encode(u8aConcat([
input,
sshash(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1)
]));
}
function decodeSubstrateAddress(address, ignoreChecksum, ss58Format = -1) {
let realError = null;
try {
const decoded = base58.decode(address);
const allowedEncodedLengths = [3, 4, 6, 10, 35, 36, 37, 38];
if (!allowedEncodedLengths.includes(decoded.length)) {
realError = new Error(`key length is not valid, decoded key length is ${decoded.length}, valid values are ${allowedEncodedLengths.join(", ")}`);
throw realError;
}
const [isValid, endPos, ss58Length, ss58Decoded] = checkAddressChecksum(decoded);
if (!ignoreChecksum && !isValid) {
realError = new Error(`Invalid decoded address checksum`);
throw realError;
}
if (![-1, ss58Decoded].includes(ss58Format)) {
realError = new Error(`Expected ss58Format ${ss58Format}, received ${ss58Decoded}`);
throw realError;
}
const publicKey = decoded.slice(ss58Length, endPos);
const hex = u8aToHex(publicKey);
return {
u8a: publicKey,
hex,
bigint: BigInt(hex)
};
} catch (error) {
throw realError ? realError : new Error(`Decoding ${address}: ${error.message}`);
}
}
var compareSubstrateAddresses = (address1, address2) => {
const addr1 = typeof address1 === "string" ? address1 : address1.Substrate || address1.substrate;
const addr2 = typeof address2 === "string" ? address2 : address2.Substrate || address2.substrate;
if (!addr1 || !addr2) {
return false;
}
try {
const decoded1 = decodeSubstrateAddress(addr1);
const decoded2 = decodeSubstrateAddress(addr2);
return decoded1.bigint === decoded2.bigint;
} catch (e) {
return false;
}
};
var addressToEvm = (address, ignoreChecksum) => {
const truncated = decodeSubstrateAddress(address, ignoreChecksum).u8a.subarray(0, 20);
return normalizeEthereumAddress(u8aToHex(truncated));
};
var EVM_PREFIX_U8A = new Uint8Array([101, 118, 109, 58]);
var evmToAddress = (evmAddress, ss58Format = 42) => {
validate.ethereumAddress(evmAddress);
const message = u8aConcat([EVM_PREFIX_U8A, hexToU8a(evmAddress)]);
return encodeSubstrateAddress(blake2AsU8a(message), ss58Format);
};
// src/utils/address/crossAccountId.ts
var guessAddressAndExtractItNormalizedSafe = (address) => {
if (typeof address === "object") {
if (is.substrateAddressObject(address))
return normalize.substrateAddress(address.Substrate);
else if (is.substrateAddressObjectUncapitalized(address))
return normalize.substrateAddress(address.substrate);
else if (is.ethereumAddressObject(address))
return normalizeEthereumAddress(address.Ethereum);
else if (is.ethereumAddressObjectUncapitalized(address))
return normalizeEthereumAddress(address.ethereum);
else
return null;
}
if (typeof address === "string") {
if (is.substrateAddress(address))
return normalizeSubstrateAddress(address);
else if (is.ethereumAddress(address))
return normalizeEthereumAddress(address);
else
return null;
}
return null;
};
var guessAddressAndExtractItNormalized = (address) => {
const result = guessAddressAndExtractItNormalizedSafe(address);
if (!result) {
throw new Error(`Passed address is not a valid address string or object: ${JSON.stringify(address).slice(0, 100)}`);
}
return result;
};
var addressToCrossAccountId = (address) => {
if (is.substrateAddress(address)) {
return { Substrate: address };
} else if (is.ethereumAddress(address)) {
return { Ethereum: address };
}
throw new Error(`Passed address ${address} is not substrate nor ethereum address`);
};
var addressToCrossAccountIdNormalized = (address) => {
if (is.substrateAddress(address)) {
return { Substrate: normalize.substrateAddress(address) };
} else if (is.ethereumAddress(address)) {
return { Ethereum: normalize.ethereumAddress(address) };
}
throw new Error(`Passed address ${address} is not substrate nor ethereum address`);
};
var substrateNormalizedWithMirrorIfEthereum = (address) => {
const addressObject = addressToCrossAccountId(address);
return addressObject.Substrate ? normalizeSubstrateAddress(addressObject.Substrate) : mirror.ethereumToSubstrate(addressObject.Ethereum);
};
// src/utils/address/index.ts
var ETH_ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
var validate = {
substrateAddress: (address) => {
decodeSubstrateAddress(address);
return true;
},
ethereumAddress: (address) => {
if (!is.ethereumAddress(address)) {
throw new Error(`address "${address}" is not valid ethereum address`);
}
return true;
},
collectionAddress: (address) => {
if (!is.collectionAddress(address)) {
throw new Error(`address ${address} is not a collection address`);
}
return true;
},
nestingAddress: (address) => {
if (!is.nestingAddress(address)) {
throw new Error(`address ${address} is not a nesting address`);
}
return true;
},
collectionId: (collectionId) => {
if (!is.collectionId(collectionId)) {
throw new Error(`collectionId should be a number between 0 and 0xffffffff`);
}
return true;
},
tokenId: (tokenId) => {
if (!is.tokenId(tokenId)) {
throw new Error(`collectionId should be a number between 0 and 0xffffffff`);
}
return true;
}
};
var is = {
substrateAddress: (address) => {
try {
decodeSubstrateAddress(address);
return true;
} catch {
return false;
}
},
ethereumAddress: (address) => {
return typeof address === "string" && address.length === 42 && !!address.match(ETH_ADDRESS_REGEX);
},
collectionAddress: (address) => {
return is.ethereumAddress(address) && address.toLowerCase().startsWith(COLLECTION_ADDRESS_PREFIX2);
},
nestingAddress: (address) => {
return is.ethereumAddress(address) && address.toLowerCase().startsWith(NESTING_PREFIX2);
},
collectionId: (collectionId) => {
return !(typeof collectionId !== "number" || isNaN(collectionId) || collectionId < 0 || collectionId > 4294967295);
},
tokenId: (tokenId) => {
return !(typeof tokenId !== "number" || isNaN(tokenId) || tokenId < 0 || tokenId > 4294967295);
},
crossAccountId(obj) {
return is.substrateAddressObject(obj) || is.ethereumAddressObject(obj);
},
crossAccountIdUncapitalized(obj) {
return is.substrateAddressObjectUncapitalized(obj) || is.ethereumAddressObjectUncapitalized(obj);
},
substrateAddressObject(obj) {
return typeof obj === "object" && typeof obj?.Substrate === "string" && is.substrateAddress(obj.Substrate);
},
ethereumAddressObject(obj) {
return typeof obj === "object" && typeof obj?.Ethereum === "string" && is.ethereumAddress(obj.Ethereum);
},
substrateAddressObjectUncapitalized(obj) {
return typeof obj === "object" && typeof obj?.substrate === "string" && is.substrateAddress(obj.substrate);
},
ethereumAddressObjectUncapitalized(obj) {
return typeof obj === "object" && typeof obj?.ethereum === "string" && is.ethereumAddress(obj.ethereum);
}
};
var collection = {
idToAddress: collectionIdToEthAddress,
addressToId: ethAddressToCollectionId
};
var nesting = {
idsToAddress: collectionIdAndTokenIdToNestingAddress,
addressToIds: nestingAddressToCollectionIdAndTokenId
};
var to = {
crossAccountId: addressToCrossAccountId,
crossAccountIdNormalized: addressToCrossAccountIdNormalized,
substrateNormalizedOrMirrorIfEthereum: substrateNormalizedWithMirrorIfEthereum
};
var extract = {
normalizedAddressFromObject: guessAddressAndExtractItNormalized,
normalizedAddressFromObjectSafe: guessAddressAndExtractItNormalizedSafe,
crossAccountIdFromObject: (obj) => {
return addressToCrossAccountId(guessAddressAndExtractItNormalized(obj));
},
crossAccountIdFromObjectNormalized: (obj) => {
return addressToCrossAccountId(guessAddressAndExtractItNormalized(obj));
}
};
var mirror = {
substrateToEthereum: addressToEvm,
ethereumToSubstrate: evmToAddress
};
var normalize = {
substrateAddress: normalizeSubstrateAddress,
ethereumAddress: normalizeEthereumAddress
};
var compare = {
substrateAddresses: compareSubstrateAddresses,
ethereumAddresses: compareEthereumAddresses
};
var substrate = {
encode: encodeSubstrateAddress,
decode: decodeSubstrateAddress,
compare: compareSubstrateAddresses
};
var Address = {
constants: constants_exports2,
is,
validate,
collection,
nesting,
to,
extract,
mirror,
normalize,
compare,
substrate,
algorithms: imports_exports,
StringUtils: stringUtils_exports
};
// src/utils/index.ts
var StringUtils = stringUtils_exports;
var Browser = {
checkEnvironmentIsBrowser: (safe) => {
if (typeof window === "undefined") {
if (safe) {
return false;
} else {
throw new Error("cannot sign with extenion not in browser");
}
}
return true;
}
};
var UniqueUtils = {
Browser,
StringUtils,
Address: address_exports
};
// src/ethereum/extensionTools.ts
var extensionTools_exports = {};
__export(extensionTools_exports, {
requestAccounts: () => requestAccounts,
safeGetAccounts: () => safeGetAccounts
});
var requestAccounts = async () => {
if (typeof window === "undefined") {
throw new Error(`Cannot access window. It's necessary`);
}
if (!window.ethereum) {
throw new Error("No window.ethereum found");
}
let accounts = [];
try {
accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
} catch (err) {
if (err.code === 4001) {
throw new Error("User rejected");
}
throw err;
}
return accounts;
};
var safeGetAccounts = async () => {
if (typeof window === "undefined" || !window.ethereum) {
return { extensionFound: false, accounts: [] };
}
const accounts = await window.ethereum.request({ method: "eth_accounts" });
return { extensionFound: true, accounts };
};
// src/ethereum/index.ts
var Ethereum = {
extension: extensionTools_exports
};
// src/substrate/extrinsicTools.ts
var extrinsicTools_exports = {};
__export(extrinsicTools_exports, {
findEventDataBySectionAndMethod: () => findEventDataBySectionAndMethod,
findManyEventsDataBySectionAndMethod: () => findManyEventsDataBySectionAndMethod,
sendTransaction: () => sendTransaction,
signAndSendTransaction: () => signAndSendTransaction,
signTransaction: () => signTransaction
});
// src/utils/errors.ts
var ValidationError = class extends TypeError {
constructor(message) {
super(message);
this.name = "ValidationError";
}
};
var ExtrinsicError = class extends Error {
constructor(txResult, errMessage, label) {
if (!label) {
const info = txResult.dispatchInfo?.toHuman();
label = `transaction ${info?.section}${info?.method}`;
}
super(`Transaction failed: "${errMessage}"${label ? " for" + label : ""}.`);
this.txResult = txResult;
}
};
// src/substrate/extrinsicTools.ts
var signerIs = {
keyring(signer) {
return typeof signer.sign === "function";
},
extensionAccount(signer) {
const address = signer.address;
return UniqueUtils.Address.is.substrateAddress(address) && typeof signer.meta.source === "string";
}
};
var findEventDataBySectionAndMethod = (txResult, section, method) => {
return txResult.events.find((event) => event.event.section === section && event.event.method === method)?.event.data;
};
var findManyEventsDataBySectionAndMethod = (txResult, section, method) => {
return txResult.events.filter((event) => event.event.section === section && event.event.method === method).map((event) => event.event.data).filter((data) => !!data);
};
var getTransactionStatus = ({ events, status }) => {
if (status.isReady || status.isBroadcast) {
return "NOT_READY" /* NOT_READY */;
}
if (status.isInBlock || status.isFinalized) {
if (events.find((e) => e.event.data.method === "ExtrinsicFailed")) {
return "FAIL" /* FAIL */;
}
if (events.find((e) => e.event.data.method === "ExtrinsicSuccess")) {
return "SUCCESS" /* SUCCESS */;
}
}
return "FAIL" /* FAIL */;
};
var signTransaction = async (tx, signer, label = "") => {
if (signerIs.keyring(signer)) {
return tx.signAsync(signer);
}
if (signerIs.extensionAccount(signer)) {
if (typeof window === "undefined") {
throw new Error("cannot sign with extenion not in browser");
}
const extension = getPolkadotExtensionDapp();
const injector = await extension.web3FromAddress(signer.address);
return tx.signAsync(signer.address, { signer: injector.signer });
}
throw new Error("Attempt to sign failed: no keyring or valid substrate address to sign by extension provided");
};
var sendTransaction = async (tx, label = "") => {
if (!label) {
const { section, method } = tx.unwrap().method.toHuman();
label = `transaction ${section}.${method}`;
}
return new Promise(async (resolve, reject) => {
let unsub = await tx.send((txResult) => {
const status = getTransactionStatus(txResult);
if (status === "SUCCESS" /* SUCCESS */) {
unsub();
resolve(txResult);
} else if (status === "FAIL" /* FAIL */) {
let errMessage = "";
if (txResult.dispatchError?.isModule) {
const decoded = tx.registry.findMetaError(txResult.dispatchError.asModule);
const { docs, name, section } = decoded;
errMessage = `${section}.${name}: ${docs.join(" ")}`;
} else {
errMessage = txResult.dispatchError?.toString() || "Unknown error";
}
unsub();
reject(new ExtrinsicError(txResult, errMessage, label));
}
});
});
};
var signAndSendTransaction = async (tx, signer, label = "") => {
return await sendTransaction(await signTransaction(tx, signer));
};
// src/substrate/extensionTools.ts
var extensionTools_exports2 = {};
__export(extensionTools_exports2, {
connectAs: () => connectAs,
getAllAccounts: () => getAllAccounts
});
var connectAs = async (appName) => {
UniqueUtils.Browser.checkEnvironmentIsBrowser();
const extension = getPolkadotExtensionDapp();
await extension.web3Enable(appName);
};
var getAllAccounts = async () => {
UniqueUtils.Browser.checkEnvironmentIsBrowser();
const extension = getPolkadotExtensionDapp();
return await extension.web3Accounts();
};
// src/substrate/signerTools.ts
var signerTools_exports = {};
__export(signerTools_exports, {
createKeyring: () => createKeyring,
keyringFromSeed: () => keyringFromSeed
});
var keyringFromSeed = (seed, keypairType = "sr25519", ss58Format = 42) => {
const keyring = createKeyring({ type: keypairType, ss58Format });
return keyring.addFromUri(seed);
};
var createKeyring = (options) => {
const { Keyring } = getPolkadotKeyring();
return new Keyring(options);
};
// src/substrate/extrinsics/AbstractExtrinsic.ts
var AbstractExtrinsic = class {
constructor(api, tx, params) {
this.api = api;
this.tx = tx;
this.params = params;
}
get isSigned() {
return this.tx.isSigned;
}
verifySignature() {
throw new Error("Unimplemented");
}
getRawTx() {
return this.tx;
}
async sign(signer) {
this.tx = await signTransaction(this.tx, signer);
return this;
}
async send(options) {
return await this.processResult(await sendTransaction(this.tx), options);
}
async signAndSend(signer, options) {
await this.sign(signer);
return await this.send(options);
}
async getPaymentInfo(fromAddress) {
const result = await this.tx.paymentInfo(fromAddress);
return result.partialFee.toBigInt();
}
async getBaseResult(txResult, options) {
const blockHash = txResult.status.asInBlock.toString();
const blockNumber = options?.getBlockNumber && !!blockHash ? (await this.api.rpc.chain.getBlock(blockHash)).block.header.number.toNumber() : void 0;
const extrinsicInfo = {
blockHash,
txHash: txResult.txHash.toString(),
txIndex: txResult.txIndex,
blockNumber
};
return {
txResult,
extrinsicInfo
};
}
async processResult(txResult, options) {
return await this.getBaseResult(txResult, options);
}
};
var TransactionFromRawTx = class extends AbstractExtrinsic {
constructor(api, tx, options) {
const transaction = typeof tx === "string" ? api.tx(tx) : tx;
super(api, transaction, tx);
}
};
// src/substrate/extrinsics/common/ExtrinsicTransferCoins.ts
var ExtrinsicTransferCoins = class extends AbstractExtrinsic {
constructor(api, params, options) {
const method = options?.dontKeepAccountAlive ? "transfer" : "transferKeepAlive";
const tx = api.tx.balances[method](params.toAddress, params.amountInWei);
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "balances", "Transfer");
const isSuccess = !!data && UniqueUtils.Address.compare.substrateAddresses(this.tx.signer.toString(), data[0].toString()) && UniqueUtils.Address.compare.substrateAddresses(this.params.toAddress, data[1].toString()) && data[2].eq(this.params.amountInWei);
return {
...result,
isSuccess
};
}
};
// src/coin/index.ts
var coin_exports = {};
__export(coin_exports, {
Coin: () => Coin,
opal: () => opal,
quartz: () => quartz,
unique: () => unique
});
// src/coin/coin.ts
var Coin = class {
constructor(options) {
this.symbol = options.symbol;
this.weiSymbol = options.weiSymbol;
this.decimals = options.decimals;
const decimalsBigInt = BigInt(options.decimals);
this.oneCoinInWei = 10n ** decimalsBigInt;
this.hwei = 10n ** (decimalsBigInt / 2n);
}
static createUnknown18DecimalsCoin() {
return new Coin({
symbol: "Unit",
weiSymbol: "wei",
decimals: 18
});
}
getOptions() {
return {
symbol: this.symbol,
decimals: this.decimals,
weiSymbol: this.weiSymbol
};
}
getFractionalPart(wei) {
const str = wei.toString();
if (str.length <= this.decimals)
return this.bigintFromWei(wei);
return BigInt(str.slice(str.length - this.decimals));
}
getIntegerPart(wei) {
const str = wei.toString();
if (str.length <= this.decimals)
return 0n;
return BigInt(str.slice(0, str.length - this.decimals));
}
bigintFromWei(wei) {
if (typeof wei === "bigint") {
return wei;
} else if (typeof wei === "string") {
if (!wei.match(/^\d+$/)) {
throw new Error("wei should be string of digits");
}
return BigInt(wei);
} else {
throw new Error("wei should be bigint or string");
}
}
format(wei, decimalPoints = 6) {
return this.formatWithoutCurrency(wei, decimalPoints) + ` ${this.symbol}`;
}
formatFullLength(wei) {
return this.format(wei, this.decimals);
}
formatWithoutCurrency(wei, decimalPoints = 6) {
if (typeof decimalPoints !== "number") {
throw new Error(`decimalPoints should be number`);
}
if (!(Math.round(decimalPoints) === decimalPoints)) {
throw new Error("decimalPoints should be integer number");
}
if (decimalPoints < 0) {
throw new Error(`decimal points should be in range GTE 0`);
}
if (decimalPoints > this.decimals) {
decimalPoints = this.decimals;
}
const intPart = this.getIntegerPart(wei);
const fracPart = this.getFractionalPart(wei);
const nonSignificantPartLength = this.decimals - decimalPoints;
const fracPartIsTooSmall = fracPart < 10n ** BigInt(nonSignificantPartLength);
if (!decimalPoints || fracPartIsTooSmall) {
return intPart.toString();
}
const fracPartStr = fracPart.toString().padStart(18, "0").slice(0, decimalPoints).replace(/\.?0*$/, "");
return `${intPart}.${fracPartStr}`;
}
dangerouslyCoinsToWei(coins) {
if (coins < 0) {
throw new Error(`coins to wei: coins should be >= 0, received ${coins}`);
}
const intPart = Math.floor(coins);
if (intPart !== 0) {
return this.coinsToWei(coins.toString());
} else {
return this.coinsToWei((coins + 1).toString()) - this.oneCoinInWei;
}
}
coinsToWei(coins) {
const parts = coins.trim().match(/^(\d*(\.\d*)?)/);
if (!parts || !parts[1]) {
throw new Error(`coinsToWei: could not parse input: ${coins}`);
}
const [intPart, fracPart] = parts[1].split(".");
const finalFracPart = fracPart ? BigInt(fracPart.padEnd(18, "0")) : 0n;
return BigInt(intPart) * this.oneCoinInWei + finalFracPart;
}
};
// src/coin/index.ts
var quartz = new Coin({
symbol: "QTZ",
weiSymbol: "wei",
decimals: 18
});
var unique = new Coin({
symbol: "UNQ",
weiSymbol: "wei",
decimals: 18
});
var opal = new Coin({
symbol: "OPL",
weiSymbol: "wei",
decimals: 18
});
// src/substrate/SubstrateCommon.ts
var SubstrateCommon = class {
constructor() {
this._ss58Prefix = 42;
this._coin = Coin.createUnknown18DecimalsCoin();
}
get api() {
if (!this._api || !this._api.isConnected) {
throw new Error(`Not connected to the WS RPC. Please call 'connect' method first.`);
}
return this._api;
}
get ss58Prefix() {
return this._ss58Prefix;
}
get coin() {
return this._coin;
}
async connect(wsEndpoint, options) {
try {
new URL(wsEndpoint);
} catch {
throw new Error(`Invalid WS RPC URL: ${wsEndpoint}`);
}
const polkadotApi = getPolkadotApi();
const definitions = options?.uniqueRpcDefinitionsName ? rpcDefinitions[options?.uniqueRpcDefinitionsName] : rpcDefinitions.unique;
this._api = new polkadotApi.ApiPromise({
provider: new polkadotApi.WsProvider(wsEndpoint),
rpc: {
unique: definitions
}
});
if (!options?.dontAwaitApiIsReady) {
await this._api.isReady;
this._coin = new Coin({
symbol: this._api.registry.chainTokens[0],
decimals: this._api.registry.chainDecimals[0],
weiSymbol: "wei"
});
this._ss58Prefix = this._api.registry.chainSS58 || 42;
}
return this;
}
async disconnect() {
if (this._api?.isConnected) {
await this._api?.disconnect();
}
return this;
}
getApi() {
return this._api;
}
get isConnected() {
return this._api?.isConnected || false;
}
transferCoins(params, options) {
return new ExtrinsicTransferCoins(this.api, params, options);
}
createTransactionFromRawTx(tx, options) {
return new TransactionFromRawTx(this.api, tx, options);
}
async getBalance(address) {
const result = await this.api.query.system.account(address);
try {
return BigInt(result.data.free.toString());
} catch (err) {
throw new Error(`Cannot cast account result to free balance`);
}
}
async getChainProperties() {
const result = (await this.api.rpc.system.properties()).toHuman();
return result;
}
};
// src/substrate/extrinsics/unique/ExtrinsicCreateCollection.ts
var ExtrinsicCreateCollection = class extends AbstractExtrinsic {
constructor(api, params, options) {
const collection2 = JSON.parse(JSON.stringify(params.collection));
if (!collection2.mode) {
collection2.mode = { nft: null };
}
for (const fieldName of ["name", "description", "tokenPrefix"]) {
;
collection2[fieldName] = StringUtils.str2vec(collection2[fieldName]);
}
const tx = api.tx.unique.createCollectionEx(collection2);
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "common", "CollectionCreated");
const collectionId = !!data && parseInt(data[0].toString(), 10) || null;
if (!collectionId) {
throw new ExtrinsicError(txResult, "No collection id found");
}
return {
...result,
collectionId
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicAddCollectionAdmin.ts
var ExtrinsicAddCollectionAdmin = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.addCollectionAdmin(params.collectionId, address_exports.to.crossAccountId(params.newAdminAddress));
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "CollectionAdminAdded");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10));
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicRemoveCollectionAdmin.ts
var ExtrinsicRemoveCollectionAdmin = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.removeCollectionAdmin(params.collectionId, address_exports.to.crossAccountId(params.adminAddress));
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "CollectionAdminRemoved");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10));
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicSetCollectionSponsor.ts
var ExtrinsicSetCollectionSponsor = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.setCollectionSponsor(params.collectionId, params.newSponsorAddress);
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "CollectionSponsorSet");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10));
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicConfirmSponsorship.ts
var ExtrinsicConfirmSponsorship = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.confirmSponsorship(params.collectionId);
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "SponsorshipConfirmed");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10));
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicChangeCollectionOwner.ts
var ExtrinsicChangeCollectionOwner = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.changeCollectionOwner(params.collectionId, params.newOwnerAddress);
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "CollectionOwnedChanged");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10));
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicRemoveCollectionSponsor.ts
var ExtrinsicRemoveCollectionSponsor = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.removeCollectionSponsor(params.collectionId);
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "CollectionSponsorRemoved");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10));
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicRemoveFromAllowList.ts
var ExtrinsicRemoveFromAllowList = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.removeFromAllowList(params.collectionId, address_exports.to.crossAccountId(params.address));
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "AllowListAddressRemoved");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10)) && !!data[1].toString();
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicAddToAllowList.ts
var ExtrinsicAddToAllowList = class extends AbstractExtrinsic {
constructor(api, params, options) {
const tx = api.tx.unique.addToAllowList(params.collectionId, address_exports.to.crossAccountId(params.address));
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "unique", "AllowListAddressAdded");
const isSuccess = !!data && !isNaN(parseInt(data[0].toString(), 10)) && !!data[1].toString();
return {
...result,
isSuccess
};
}
};
// src/substrate/extrinsics/unique/utils.ts
var validateAndFixTokenOwner = (token) => {
let owner = address_exports.is.crossAccountId(token.owner) ? token.owner : null;
if (owner === null) {
if (typeof token.owner !== "string") {
throw new Error(`create token: owner should be valid object or string, got ${typeof token.owner}: ${token.owner}`);
}
if (UniqueUtils.Address.is.ethereumAddress(token.owner)) {
owner = { Ethereum: token.owner };
} else if (UniqueUtils.Address.is.substrateAddress(token.owner)) {
owner = { Substrate: token.owner };
} else {
throw new Error(`create token: owner should be valid ethereum or substrate address, got "${token.owner}"`);
}
}
return {
...token,
owner
};
};
// src/substrate/extrinsics/unique/ExtrinsicCreateNftToken.ts
var ExtrinsicCreateNftToken = class extends AbstractExtrinsic {
constructor(api, params, options) {
const token = validateAndFixTokenOwner(JSON.parse(JSON.stringify(params.token)));
const tx = api.tx.unique.createItem(params.collectionId, token.owner, { NFT: { properties: token.properties } });
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const data = findEventDataBySectionAndMethod(txResult, "common", "ItemCreated");
if (!data) {
throw new Error(`No event common.ItemCreated found`);
}
const collectionId = parseInt(data[0].toString(), 10);
const tokenId = parseInt(data[1].toString(), 10);
const owner = data[2].toJSON();
if (!tokenId) {
throw new ExtrinsicError(txResult, "No token id found");
}
return {
...result,
collectionId,
tokenId,
owner
};
}
};
// src/substrate/extrinsics/unique/ExtrinsicCreateMultipleNftTokens.ts
var ExtrinsicCreateMultipleNftTokens = class extends AbstractExtrinsic {
constructor(api, params, options) {
if (!Array.isArray(params.tokens)) {
throw new Error(`params.tokens should be an array`);
}
if (params.tokens.length > 100) {
throw new Error(`Minting multiple tokens: not more than 100 tokens at a time (got ${params.tokens.length} tokens)`);
}
const tokens = JSON.parse(JSON.stringify(params.tokens)).map(validateAndFixTokenOwner);
const tx = api.tx.unique.createMultipleItemsEx(params.collectionId, { NFT: tokens });
super(api, tx, params);
}
async processResult(txResult, options) {
const result = await this.getBaseResult(txResult, options);
const successData = findEventDataBySectionAndMethod(txResult, "system", "ExtrinsicSuccess");
const tokenDataElements = findManyEventsDataBySectionAndMethod(txResult, "common", "ItemCreated");
const tokens = tokenDataElements.map((data) => {
const tokenId = !!data && parseInt(data[1].toString(), 10);
const owner = !!data && data[2].toJSON();
return { tokenId, owner };
});
return {
...result,
tokens
};
}
};
// src/schema/types.ts
var types_exports = {};
__export(types_exports, {
AttributeType: () => AttributeType,
AttributeTypeValues: () => AttributeTypeValues,
COLLECTION_SCHEMA_NAME: () => COLLECTION_SCHEMA_NAME,
IntegerAttributeTypes: () => IntegerAttributeTypes,
NumberAttributeTypes: () => NumberAttributeTypes,
StringAttributeTypes: () => StringAttributeTypes,
URL_TEMPLATE_INFIX: () => URL_TEMPLATE_INFIX
});
var URL_TEMPLATE_INFIX = "{infix}";
var AttributeType = /* @__PURE__ */ ((AttributeType2) => {
AttributeType2["integer"] = "integer";
AttributeType2["float"] = "float";
AttributeType2["boolean"] = "boolean";
AttributeType2["timestamp"] = "timestamp";
AttributeType2["string"] = "string";
AttributeType2["url"] = "url";
AttributeType2["isoDate"] = "isoDate";
AttributeType2["time"] = "time";
AttributeType2["colorRgba"] = "colorRgba";
return AttributeType2;
})(AttributeType || {});
var NumberAttributeTypes = [
"integer" /* integer */,
"float" /* float */,
"boolean" /* boolean */,
"timestamp" /* timestamp */
];
var IntegerAttributeTypes = [
"integer" /* integer */,
"boolean" /* boolean */,
"timestamp" /* timestamp */
];
var StringAttributeTypes = [
"string" /* string */,
"url" /* url */,
"isoDate" /* isoDate */,
"time" /* time */,
"colorRgba" /* colorRgba */
];
var AttributeTypeValues = getEnumValues(AttributeType);
var COLLECTION_SCHEMA_NAME = /* @__PURE__ */ ((COLLECTION_SCHEMA_NAME2) => {
COLLECTION_SCHEMA_NAME2["unique"] = "unique";
COLLECTION_SCHEMA_NAME2["old"] = "_old_";
COLLECTION_SCHEMA_NAME2["ERC721Metadata"] = "ERC721Metadata";
return COLLECTION_SCHEMA_NAME2;
})(COLLECTION_SCHEMA_NAME || {});
// src/schema/tools/validators/index.ts
var validators_exports = {};
__export(validators_exports, {
LANG_REGEX: () => LANG_REGEX,
RGBA_REGEX: () => RGBA_REGEX,
RGB_REGEX: () => RGB_REGEX,
checkSafeFactory: () => checkSafeFactory,
isPlainObject: () => isPlainObject,
validateAndParseSemverString: () => validateAndParseSemverString,
validateAttributeKey: () => validateAttributeKey,
validateAttributesSchemaSingleAttribute: () => validateAttributesSchemaSingleAttribute,
validateBoxedNumberWithDefault: () => validateBoxedNumberWithDefault,
validateCollectionAttributesSchema: () => validateCollectionAttributesSchema,
validateCollectionTokenPropertyPermissions: () => validateCollectionTokenPropertyPermissions,
validateFieldByType: () => validateFieldByType,
validateLocalizedStringWithDefault: () => validateLocalizedStringWithDefault,
validateLocalizedStringWithDefaultSafe: () => validateLocalizedStringWithDefaultSafe,
validateNumber: () => validateNumber,
validateSingleTokenPropertyPermission: () => validateSingleTokenPropertyPermission,
validateURL: () => validateURL,
validateURLSafe: () => validateURLSafe,
validateUniqueCollectionSchema: () => validateUniqueCollectionSchema,
validateUniqueToken: () => validateUniqueToken,
validateUrlTemplateString: () => validateUrlTemplateString,
validateUrlTemplateStringSafe: () => validateUrlTemplateStringSafe,
validateUrlWithHashObject: () => validateUrlWithHashObject,
validateValueVsAttributeType: () => validateValueVsAttributeType
});
// src/utils/semver.ts
var Semver = class {
constructor(semver) {
this._major = semver[0];
this._minor = semver[1];
this._patch = semver[2];
}
get major() {
return this._major;
}
get minor() {
return this._minor;
}
get patch() {
return this._patch;
}
toString() {
return `${this.major}.${this.minor}.${this.patch}`;
}
static parseToArray(version) {
if (typeof version !== "string")
return null;
const [main] = version.split("+")[0].split("-").map((i) => i.split("."));
const major = parseInt(main[0]);
if (isNaN(major))
return null;
const minor = parseInt(main[1]);
const patch = parseInt(main[2]);
return [major, isNaN(minor) ? 0 : minor, isNaN(patch) ? 0 : patch];
}
static fromString(version) {
const parsed = Semver.parseToArray(version);
if (!parsed)
throw new Error(`Semver.fromString: wrong version string value: "${version}"`);
return new Semver(parsed);
}
static isValid(version) {
return typeof version === "string" && Semver.parseToArray(version) !== null;
}
isGteThan(version) {
const parsed = Semver.parseToArray(version);
if (!parsed)
return false;
if (this._major > parsed[0])
return true;
if (this._major < parsed[0])
return false;
if (this._minor > parsed[1])
return true;
if (this._minor < parsed[1])
return false;
return this._patch >= parsed[2];
}
isLessThan(version) {
const parsed = Semver.parseToArray(version);
if (!parsed)
return false;
if (this._major < parsed[0])
return true;
if (this._major > parsed[0])
return false;
if (this._minor < parsed[1])
return true;
if (this._minor > parsed[1])
return false;
return this._patch < parsed[2];
}
isEqual(version) {
const parsed = Semver.parseToArray(version);
if (!parsed)
return false;
return this._major === parsed[0] && this._minor === parsed[1] && this._patch === parsed[2];
}
};
// src/schema/tools/validators/constants.ts
var RGB_REGEX = /^#[A-Fa-f0-9]{6}$/;
var RGBA_REGEX = /^#[A-Fa-f0-9]{8}$/;
var LANG_REGEX = /^[a-z]{2}(-[A-Z]{2})?$/;
// src/schema/tools/validators/common-validators.ts
var isPlainObject = (obj, varName) => {
if (typeof obj !== "object")
throw new ValidationError(`${varName} is not an object, got ${typeof obj}: ${obj}`);
if (obj === null)
throw new ValidationError(`${varName} is a null, should be valid object`);
if (obj instanceof Map)
throw new ValidationError(`${varName} is a Map, should be plain object`);
if (obj instanceof Set)
throw new ValidationError(`${varName} is a Set, should be plain object`);
if (Array.isArray(obj))
throw new ValidationError(`${varName} is an array, should be plain object`);
return true;
};
var validateNumber = (num, shouldBeInteger, varName) => {
if (typeof num !== "number" || isNaN(num)) {
throw new ValidationError(`${varName} is not a valid number, got ${num}`);
}
if (shouldBeInteger && num !== Math.round(num)) {
throw new ValidationError(`${varName} is not an integer number, got ${num}`);
}
return true;
};
var validateAttributeKey = (num, varName) => {
let isOk = false;
if (typeof num === "number") {
isOk = num === Math.round(num);
} else if (typeof num === "string") {
const parsed = parseFloat(num);
isOk = !isNaN(parsed) && parsed === Math.round(parsed);
}
if (!isOk) {
throw new ValidationError(`${varName}["${String(num)}"] is not a valid number key, got ${String(num)}`);
}
return true;
};
var validateLangCode = (key, varName) => {
if (typeof key !== "string") {
throw new ValidationError(`${varName}: key ${String(key)} should be a string`);
}
if (!key.match(LANG_REGEX)) {
throw new ValidationError(`${varName} should be a valid Language code string (like 'co' or 'ca-ES'), got ${key}`);
}
return true;
};
var validateURL = (url, varName) => {
if (typeof url !== "string") {
throw new ValidationError(`${varName} should be a string`);
}
try {
new URL(url);
return true;
} catch (err) {
throw new ValidationError(`${varName} should be a valid URL, got ${url}`);
}
};
var validateAndParseSemverString = (str, varName) => {
if (!Semver.isValid(str))
throw new ValidationError(`${varName} is not a valid semver string (passed ${str})`);
return Semver.fromString(str);
};
var validateLocalizedStringWithDefault = (dict, canHaveLocalization, varName) => {
isPlainObject(dict, varName);
const keys = getKeys(dict);
if (keys.length === 0) {
throw new ValidationError(`${varName} is an empty object, should have at least one key`);
}
if (!dict.hasOwnProperty("_")) {
throw new ValidationError(`${varName} is doesn't contain field "_"`);
}
if (typeof dict._ !== "string") {
throw new ValidationError(`${varName}._ is not a string`);
}
if (!canHaveLocalization && keys.length !== 1) {
throw new ValidationError(`${varName} cannot have localization strings, got object with keys ["${keys.join('", "')}"]`);
}
for (const key in dict) {
if (key === "_")
continue;
validateLangCode(key, `${varName}["${key}"]`);
if (typeof dict[key] !== "string") {
throw new ValidationError(`${varName}["${key}"] should be a string, got ${typeof key}: ${key}`);
}
}
return true;
};
var validateBoxedNumberWithDefault = (dict, shouldBeInteger, varName) => {
isPlainObject(dict, varName);
if (getKeys(dict).length === 0) {
throw new ValidationError(`${varName} is an empty object, should have at least one key`);
}
if (!dict.hasOwnProperty("_")) {
throw new ValidationError(`${varName} is doesn't contain field "_"`);
}
validateNumber(dict._, shouldBeInteger, `${varName}._`);
for (const key in dict) {
if (key === "_")
continue;
}
return true;
};
var validateUrlTemplateString = (str, varName) => {
const prefix = `TemplateUrlString is not valid, ${varName}`;
if (typeof str !== "string")
throw new ValidationError(`${prefix} is not a string, got ${str}`);
if (str.indexOf(URL_TEMPLATE_INFIX) < 0)
throw new ValidationError(`${prefix} doesn't contain "${URL_TEMPLATE_INFIX}", got ${str}`);
return true;
};
var validateUrlWithHashObject = (obj, varName) => {
isPlainObject(obj, varName);
const keysAmount = ["urlInfix", "url", "ipfsCid"].map((field) => Number(typeof obj[field] === "string")).reduce((prev, curr) => {
return prev + curr;
}, 0);
if (keysAmount !== 1) {
throw new ValidationError(`${varName} should have one and only one of "urlInfix" or "url" or "ipfsCid" string fields, got ${JSON.stringify(obj)}`);
}
if (typeof obj.url === "string") {
validateURL(obj.url, `${varName}.url`);
}
if (obj.hasOwnProperty("hash"))
validateFieldByType(obj, "hash", "string", false, varName);
return true;
};
var validateFieldByType = (obj, key, type, optional, varName) => {
isPlainObject(obj, varName);
if (optional) {
if (obj.hasOwnProperty(key) && typeof obj[key] !== type) {
throw new ValidationError(`${varName}.${String(key)} is passed and not a ${type}, got ${typeof obj[key]}: ${obj[key]}`);
}
} else {
if (!obj.hasOwnProperty(key)) {
throw new ValidationError(`${varName}.${String(key)} not found in ${varName}`);
}
if (typeof obj[key] !== type) {
throw new ValidationError(`${varName}.${String(key)} should be a ${type}, got ${typeof obj[key]}: ${obj[key]}`);
}
}
return true;
};
var validateSingleTokenPropertyPermission = (tpp, varName) => {
isPlainObject(tpp, varName);
validateFieldByType(tpp, "key", "string", false, varName);
const permissionVarName = `${varName}.permission`;
isPlainObject(tpp.permission, permissionVarName);
validateFieldByType(tpp.permission, "mutable", "boolean", false, permissionVarName);
validateFieldByType(tpp.permission, "collectionAdmin", "boolean", false, permissionVarName);
validateFieldByType(tpp.permission, "tokenOwner", "boolean", false, permissionVarName);
return true;
};
var checkSafeFactory = (fn) => {
const returnFn = (...params) => {
try {
return fn(...params);
} catch {
return false;
}
};
return returnFn;
};
var validateUrlTemplateStringSafe = checkSafeFactory(validateUrlTemplateString);
var validateURLSafe = checkSafeFactory(validateURL);
var validateLocalizedStringWithDefaultSafe = checkSafeFactory(validateLocalizedStringWithDefault);
// src/schema/tools/validators/collection-validators.ts
var validateValueVsAttributeType = (value, type, varName) => {
isPlainObject(value, varName);
if (NumberAttributeTypes.includes(type)) {
const shouldBeInteger = IntegerAttributeTypes.includes(type);
validateBoxedNumberWithDefault(value, shouldBeInteger, varName);
if (type === "boolean" /* boolean */ && ![0, 1].includes(value._)) {
throw new ValidationError(`${varName}: should be a boolean integer: 0 or 1, got ${value._}`);
}
return true;
}
if (StringAttributeTypes.includes(type)) {
const canHaveLocalization = type === "string" /* string */;
validateLocalizedStringWithDefault(value, canHaveLocalization, varName);
if (type === "isoDate" /* isoDate */ && isNaN(new Date(value._).valueOf())) {
throw new ValidationError(`${varName}: should be a valid ISO Date (YYYY-MM-DD), got ${value._}`);
}
if (type === "time" /* time */ && isNaN(new Date("1970-01-01T" + value._).valueOf())) {
throw new ValidationError(`${varName}: should be a valid time in (hh:mm or hh:mm:ss), got ${value._}`);
}
if (type === "colorRgba" /* colorRgba */ && (!value._.match(RGB_REGEX) && !value._.match(RGBA_REGEX))) {
throw new ValidationError(`${varName}: should be a valid rgb or rgba color (like "#ff00ff00"), got ${value._}`);
}
return true;
}
throw new ValidationError(`${varName}: unknown attribute type: ${type}`);
};
var validateAttributesSchemaSingleAttribute = (attr, varName) => {
isPlainObject(attr, varName);
validateLocalizedStringWithDefault(attr.name, true, `${varName}.name`);
if (attr.hasOwnProperty("optional") && typeof attr.optional !== "boolean")
throw new ValidationError(`${varName}.optional should be boolean when passed, got ${typeof attr.optional}: ${attr.optional}`);
if (attr.hasOwnProperty("isArray") && typeof attr.isArray !== "boolean") {
throw new ValidationError(`${varName}.optional should be boolean when passed, got ${typeof attr.optional}: ${attr.optional}`);
}
if (!AttributeTypeValues.includes(attr.type))
throw new ValidationError(`${varName}.type should be a valid attribute type, got ${typeof attr.type}: ${attr.type}`);
if (attr.hasOwnProperty("enumValues")) {
isPlainObject(attr.enumValues, `${varName}.enumValues`);
for (const key in attr.enumValues) {
const localVarName = `${varName}.enumValues[${key}]`;
const intKey = parseInt(key);
validateNumber(intKey, true, localVarName);
validateValueVsAttributeType(attr.enumValues[intKey], attr.type, localVarName);
}
}
return true;
};
var validateCollectionAttributesSchema = (attributes, varName) => {
isPlainObject(attributes, varName);
for (const key in attributes) {
validateAttributeKey(key, varName);
validateAttributesSchemaSingleAttribute(attributes[key], `${varName}["${key}"]`);
}
return true;
};
var validateUniqueCollectionSchema = (schema) => {
isPlainObject(schema, "Passed collection schema");
if (schema.schemaName !== "unique" /* unique */)
throw new ValidationError(`schemaName is not valid (passed ${schema.schemaName})`);
const schemaVersion = validateAndParseSemverString(schema.schemaVersion, "schemaVersion");
if (!schemaVersion.isEqual("1.0.0")) {
throw new ValidationError(`collection schema has unsupported type: ${schemaVersion.toString()}`);
}
validateUrlWithHashObject(schema.coverPicture, "coverPicture");
if (schema.hasOwnProperty("coverPicturePreview")) {
validateUrlWithHashObject(schema.coverPicturePreview, "coverPicturePreview");
}
if (!schema.attributesSchemaVersion !== !schema.attributesSchema) {
throw new ValidationError(`"attributesSchemaVersion" and "attributesSchema" should both be filled or both empty`);
}
if (schema.attributesSchemaVersion && schema.attributesSchema) {
const attributesSchemaVersion = validateAndParseSemverString(schema.attributesSchemaVersion, "attributesSchemaVersion");
if (!attributesSchemaVersion.isEqual("1.0.0")) {
throw new ValidationError(`collection attributes schema has unsupported type: ${attributesSchemaVersion.toString()}`);
}
validateCollectionAttributesSchema(schema.attributesSchema, "attributesSchema");
}
isPlainObject(schema.image, "image");
validateUrlTemplateString(schema.image.urlTemplate, "image");
if (schema.hasOwnProperty("imagePreview")) {
isPlainObject(schema.video, "video");
validateUrlTemplateString(schema.video.urlTemplate, "video");
}
if (schema.hasOwnProperty("video")) {
isPlainObject(schema.video, "video");
validateUrlTemplateString(schema.video.urlTemplate, "video");
}
if (schema.hasOwnProperty("audio")) {
isPlainObject(schema.audio, "audio");
validateUrlTemplateString(schema.audio.urlTemplate, "audio");
validateFieldByType(schema.audio, "format", "string", false, "audio");
validateFieldByType(schema.audio, "isLossless", "boolean", true, "audio");
}
if (schema.hasOwnProperty("spatialObject")) {
isPlainObject(schema.spatialObject, "spatialObject");
validateUrlTemplateString(schema.spatialObject.urlTemplate, "spatialObject");
validateFieldByType(schema.spatialObject, "format", "string", false, "spatialObject");
}
return true;
};
var validateCollectionTokenPropertyPermissions = (tpps, varName = "tokenPropertyPermissions") => {
if (!Array.isArray(tpps))
throw new ValidationError(`${varName} should be an array, got ${typeof tpps}: ${tpps}`);
tpps.forEach((tpp, index) => {
validateSingleTokenPropertyPermission(tpp, `${varName}[${index}]`);
});
return true;
};
// src/schema/tools/validators/token-validators.ts
var validateAttributeEnumKey = (schema, num, varName) => {
validateNumber(num, true, varName);
const enumKeys = getKeys(schema.enumValues || {}).map((n) => parseInt(n));
if (!enumKeys.includes(num)) {
throw new ValidationError(`${varName} value (${num}) not found in the attribute schema enum keys: [${enumKeys.join()}]`);
}
};
var validateUniqueToken = (token, collectionSchema) => {
if (collectionSchema.schemaName !== "unique" /* unique */) {
throw new ValidationError(`schemaName is not "unique" (passed ${collectionSchema.schemaName})`);
}
if (token.hasOwnProperty("name")) {
validateLocalizedStringWithDefault(token.name, true, "token.name");
}
if (token.hasOwnProperty("description")) {
validateLocalizedStringWithDefault(token.description, true, "token.description");
}
validateUrlWithHashObject(token.image, "token.image");
if (token.hasOwnProperty("imagePreview")) {
validateUrlWithHashObject(token.imagePreview, "token.imagePreview");
}
const schemaVersion = validateAndParseSemverString(collectionSchema.schemaVersion, "collectionSchema.schemaVersion");
if (token.encodedAttributes && collectionSchema.attributesSchema) {
isPlainObject(token.encodedAttributes, "token.encodedAttributes");
for (let key in collectionSchema.attributesSchema) {
const schema = collectionSchema.attributesSchema[key];
validateAttributeKey(key, "token.encodedAttributes");
const varName = `token.encodedAttributes.${key}`;
const attr = token.encodedAttributes[key];
if (!token.encodedAttributes.hasOwnProperty(key)) {
if (schema.optional) {
continue;
} else {
throw new ValidationError(`${varName} should be provided, it's not optional attribute`);
}
}
if (schema.isArray && !Array.isArray(attr)) {
throw new ValidationError(`${varName} is not array, while schema requires an array`);
}
if (!schema.isArray && Array.isArray(attr)) {
throw new ValidationError(`${varName} is an array, while schema requires to be not an array`);
}
const attrs = schema.isArray ? attr : [attr];
if (schema.enumValues) {
attrs.forEach((num, index) => {
validateAttributeEnumKey(schema, num, `${varName}[${index}]`);
});
} else {
attrs.forEach((attrElem, index) => {
validateValueVsAttributeType(attrElem, schema.type, `${varName}[${index}]`);
});
}
}
}
if (collectionSchema.hasOwnProperty("video") && token.hasOwnProperty("video")) {
validateUrlWithHashObject(token.video, "token.video");
}
if (collectionSchema.hasOwnProperty("audio") && token.hasOwnProperty("audio")) {
validateUrlWithHashObject(token.audio, "token.audio");
}
if (collectionSchema.hasOwnProperty("spatialObject") && token.hasOwnProperty("spatialObject")) {
validateUrlWithHashObject(token.spatialObject, "token.spatialObject");
}
return true;
};
// src/schema/tools/collection.ts
var collection_exports = {};
__export(collection_exports, {
decodeUniqueCollectionFromProperties: () => decodeUniqueCollectionFromProperties,
encodeCollectionSchemaToProperties: () => encodeCollectionSchemaToProperties,
generateTokenPropertyPermissionsFromCollectionSchema: () => generateTokenPropertyPermissionsFromCollectionSchema,
unpackCollectionSchemaFromProperties: () => unpackCollectionSchemaFromProperties
});
// src/schema/schemaUtils.ts
var convert2LayerObjectToProperties = (obj, separator) => {
if (typeof obj !== "object" || obj === null) {
throw new Error(`Object is not valid: ${obj}`);
}
const collectionProperties = [];
for (let key in obj) {
const value = obj[key];
if (typeof value === "object" && !(value === null || value instanceof Map || value instanceof Set || Array.isArray(value))) {
for (let secondLevelKey in value) {
const secondLevelValue = value[secondLevelKey];
collectionProperties.push({
key: `${key}${separator}${secondLevelKey}`,
value: JSON.stringify(secondLevelValue)
});
}
} else {
collectionProperties.push({
key,
value: JSON.stringify(value)
});
}
}
return collectionProperties;
};
var convertPropertyArrayTo2layerObject = (properties, separator) => {
const obj = {};
for (let { key, value } of properties) {
const keyParts = key.split(separator);
const length = keyParts.length;
if (length === 1) {
obj[key] = safeJsonParseStringOrHexString(value);
} else {
const [key2, innerKey] = keyParts;
if (typeof obj[key2] !== "object") {
obj[key2] = {};
}
obj[key2][innerKey] = safeJsonParseStringOrHexString(value);
}
}
return obj;
};
var SEPARATOR = ".";
var converters2Layers = {
objectToProperties: (obj) => {
return convert2LayerObjectToProperties(obj, SEPARATOR);
},
propertiesToObject: (arr) => {
return convertPropertyArrayTo2layerObject(arr, SEPARATOR);
}
};
var decodeTokenUrlOrInfixOrCidWithHashField = (obj, urlTemplateObj) => {
const result = {
...obj,
fullUrl: null
};
if (typeof obj.url === "string") {
result.fullUrl = obj.url;
return result;
}
const urlTemplate = urlTemplateObj?.urlTemplate;
if (typeof urlTemplate !== "string" || urlTemplate.indexOf(URL_TEMPLATE_INFIX) < 0) {
if (typeof obj.ipfsCid === "string") {
result.fullUrl = `ipfs://${obj.ipfsCid}`;
}
} else {
if (typeof obj.urlInfix === "string") {
result.fullUrl = urlTemplate.replace(URL_TEMPLATE_INFIX, obj.urlInfix);
} else if (typeof obj.ipfsCid === "string") {
result.fullUrl = urlTemplate.replace(URL_TEMPLATE_INFIX, obj.ipfsCid);
}
}
return result;
};
// src/schema/tools/collection.ts
var encodeCollectionSchemaToProperties = (schema) => {
validateUniqueCollectionSchema(schema);
return converters2Layers.objectToProperties(schema);
};
var unpackCollectionSchemaFromProperties = (properties) => {
return converters2Layers.propertiesToObject(properties);
};
var decodeUniqueCollectionFromProperties = async (collectionId, properties) => {
try {
const unpackedSchema = unpackCollectionSchemaFromProperties(properties);
validateUniqueCollectionSchema(unpackedSchema);
unpackedSchema.collectionId = collectionId;
if (unpackedSchema.coverPicture) {
unpackedSchema.coverPicture = decodeTokenUrlOrInfixOrCidWithHashField(unpackedSchema.coverPicture, unpackedSchema.image);
}
if (unpackedSchema.coverPicturePreview) {
unpackedSchema.coverPicturePreview = decodeTokenUrlOrInfixOrCidWithHashField(unpackedSchema.coverPicturePreview, unpackedSchema.image);
}
return {
result: unpackedSchema,
error: null
};
} catch (e) {
return {
result: null,
error: e
};
}
};
var generateDefaultTPPObjectForKey = (key) => ({
key,
permission: { mutable: false, collectionAdmin: true, tokenOwner: false }
});
var generateDefaultTPPsForInfixOrUrlOrCidAndHashObject = (permissions, prefix) => {
permissions.push(generateDefaultTPPObjectForKey(`${prefix}.i`));
permissions.push(generateDefaultTPPObjectForKey(`${prefix}.c`));
permissions.push(generateDefaultTPPObjectForKey(`${prefix}.u`));
permissions.push(generateDefaultTPPObjectForKey(`${prefix}.h`));
};
var generateTokenPropertyPermissionsFromCollectionSchema = (schema, options) => {
const permissions = [
generateDefaultTPPObjectForKey("n"),
generateDefaultTPPObjectForKey("d")
];
generateDefaultTPPsForInfixOrUrlOrCidAndHashObject(permissions, "i");
if (schema.hasOwnProperty("imagePreview")) {
generateDefaultTPPsForInfixOrUrlOrCidAndHashObject(permissions, "p");
}
if (schema.hasOwnProperty("video")) {
generateDefaultTPPsForInfixOrUrlOrCidAndHashObject(permissions, "v");
}
if (schema.hasOwnProperty("audio")) {
generateDefaultTPPsForInfixOrUrlOrCidAndHashObject(permissions, "au");
}
if (schema.hasOwnProperty("spatialObject")) {
generateDefaultTPPsForInfixOrUrlOrCidAndHashObject(permissions, "so");
}
if (schema.attributesSchema) {
getKeys(schema.attributesSchema).forEach((key) => {
permissions.push(generateDefaultTPPObjectForKey(`a.${key}`));
});
}
if (options?.overwriteTPPs) {
const { overwriteTPPs } = options;
if (!validateCollectionTokenPropertyPermissions(overwriteTPPs)) {
throw new Error(`overwriteTPPs are not valid`);
}
for (const tpp of overwriteTPPs) {
const index = permissions.findIndex((permission) => permission.key === tpp.key);
if (index < 0) {
permissions.push(tpp);
} else {
permissions[index] = tpp;
}
}
}
return permissions;
};
// src/schema/tools/token.ts
var token_exports = {};
__export(token_exports, {
decodeTokenFromProperties: () => decodeTokenFromProperties,
encodeTokenToProperties: () => encodeTokenToProperties,
fullDecodeTokenAttributes: () => fullDecodeTokenAttributes,
unpackEncodedTokenFromProperties: () => unpackEncodedTokenFromProperties
});
var addUrlObjectToTokenProperties = (properties, prefix, source) => {
if (typeof source.urlInfix === "string") {
properties.push({ key: `${prefix}.i`, value: source.urlInfix });
} else if (typeof source.ipfsCid === "string") {
properties.push({ key: `${prefix}.c`, value: source.ipfsCid });
} else if (typeof source.url === "string") {
properties.push({ key: `${prefix}.u`, value: source.url });
}
if (typeof source.hash === "string") {
properties.push({ key: `${prefix}.h`, value: source.hash });
}
};
var addKeyToTokenProperties = (properties, key, value) => {
let strValue = JSON.stringify(value);
properties.push({
key,
value: strValue
});
};
var encodeTokenToProperties = (token, schema) => {
validateUniqueToken(token, schema);
const properties = [];
if (token.name)
addKeyToTokenProperties(properties, "n", token.name);
if (token.description)
addKeyToTokenProperties(properties, "d", token.description);
if (token.encodedAttributes) {
for (const n in token.encodedAttributes) {
const value = token.encodedAttributes[n];
addKeyToTokenProperties(properties, `a.${n}`, value);
}
}
if (token.image)
addUrlObjectToTokenProperties(properties, "i", token.image);
if (schema.imagePreview && token.imagePreview)
addUrlObjectToTokenProperties(properties, "p", token.imagePreview);
if (schema.video && token.video)
addUrlObjectToTokenProperties(properties, "v", token.video);
if (schema.audio && token.audio)
addUrlObjectToTokenProperties(properties, "au", token.audio);
if (schema.spatialObject && token.spatialObject)
addUrlObjectToTokenProperties(properties, "so", token.spatialObject);
return properties;
};
var fillTokenFieldByKeyPrefix = (token, properties, prefix, tokenField) => {
const keysMatchingPrefix = [`${prefix}.i`, `${prefix}.u`, `${prefix}.c`, `${prefix}.h`];
if (properties.some(({ key }) => keysMatchingPrefix.includes(key)))
token[tokenField] = {};
const field = token[tokenField];
const urlInfixProperty = properties.find(({ key }) => key === keysMatchingPrefix[0]);
if (urlInfixProperty)
field.urlInfix = urlInfixProperty.value;
const urlProperty = properties.find(({ key }) => key === keysMatchingPrefix[1]);
if (urlProperty)
field.url = urlProperty.value;
const ipfsCidProperty = properties.find(({ key }) => key === keysMatchingPrefix[2]);
if (ipfsCidProperty)
field.ipfsCid = ipfsCidProperty.value;
const hashProperty = properties.find(({ key }) => key === keysMatchingPrefix[3]);
if (hashProperty)
field.hash = hashProperty.value;
};
var unpackEncodedTokenFromProperties = (properties, schema) => {
const token = {};
const nameProperty = properties.find(({ key }) => key === "n");
if (nameProperty) {
const parsedName = safeJsonParseStringOrHexString(nameProperty.value);
if (typeof parsedName !== "string") {
token.name = parsedName;
}
}
const descriptionProperty = properties.find(({ key }) => key === "d");
if (descriptionProperty) {
const parsedDescription = safeJsonParseStringOrHexString(descriptionProperty.value);
if (typeof parsedDescription !== "string") {
token.description = parsedDescription;
}
}
fillTokenFieldByKeyPrefix(token, properties, "i", "image");
fillTokenFieldByKeyPrefix(token, properties, "p", "imagePreview");
fillTokenFieldByKeyPrefix(token, properties, "v", "video");
fillTokenFieldByKeyPrefix(token, properties, "au", "audio");
fillTokenFieldByKeyPrefix(token, properties, "so", "spatialObject");
const attributeProperties = properties.filter(({ key }) => key.startsWith("a."));
if (attributeProperties.length) {
const attrs = {};
for (const attrProp of attributeProperties) {
const { key, value } = attrProp;
const parsed = safeJsonParseStringOrHexString(value);
const attributeKey = parseInt(key.split(".")[1] || "");
if (!isNaN(attributeKey) && schema.attributesSchema?.hasOwnProperty(attributeKey)) {
attrs[attributeKey] = parsed;
}
}
token.encodedAttributes = attrs;
}
return token;
};
var decodeTokenFromProperties = async (collectionId, tokenId, rawToken, schema) => {
const unpackedToken = unpackEncodedTokenFromProperties(rawToken.properties, schema);
console.log("UNPACKED TOKEN");
console.log(unpackedToken);
try {
validateUniqueToken(unpackedToken, schema);
} catch (e) {
return {
result: null,
error: e
};
}
const token = {
owner: rawToken.owner,
tokenId,
collectionId,
attributes: fullDecodeTokenAttributes(unpackedToken, schema),
image: decodeTokenUrlOrInfixOrCidWithHashField(unpackedToken.image, schema.image)
};
if (token.owner.Ethereum && UniqueUtils.Address.is.nestingAddress(token.owner.Ethereum)) {
token.nestingParentToken = UniqueUtils.Address.nesting.addressToIds(token.owner.Ethereum);
}
if (unpackedToken.name)
token.name = unpackedToken.name;
if (unpackedToken.description)
token.description = unpackedToken.description;
if (unpackedToken.imagePreview) {
token.imagePreview = decodeTokenUrlOrInfixOrCidWithHashField(unpackedToken.imagePreview, schema.imagePreview);
}
if (unpackedToken.video) {
token.video = decodeTokenUrlOrInfixOrCidWithHashField(unpackedToken.video, schema.video);
}
if (unpackedToken.audio) {
token.audio = decodeTokenUrlOrInfixOrCidWithHashField(unpackedToken.audio, schema.audio);
}
if (unpackedToken.spatialObject) {
token.spatialObject = decodeTokenUrlOrInfixOrCidWithHashField(unpackedToken.spatialObject, schema.spatialObject);
}
return {
result: token,
error: null
};
};
var fullDecodeTokenAttributes = (token, collectionSchema) => {
const attributes = {};
if (!token.encodedAttributes)
return {};
const entries = getEntries(token.encodedAttributes);
for (const entry of entries) {
const [key, rawValue] = entry;
const schema = collectionSchema.attributesSchema?.[key];
if (!schema)
continue;
let value = rawValue;
if (schema.enumValues) {
if (schema.isArray && Array.isArray(rawValue)) {
value = rawValue.map((v) => typeof v === "number" ? schema.enumValues?.[v] : null).filter((v) => !!v);
} else {
if (typeof rawValue === "number") {
value = schema.enumValues[rawValue];
}
}
}
attributes[key] = {
name: schema.name,
value,
isArray: schema.isArray || false,
type: schema.type,
rawValue,
isEnum: !!schema.enumValues
};
}
return attributes;
};
// src/schema/tools/oldSchemaDecoder.ts
var oldSchemaDecoder_exports = {};
__export(oldSchemaDecoder_exports, {
decodeOldSchemaCollection: () => decodeOldSchemaCollection,
decodeOldSchemaToken: () => decodeOldSchemaToken
});
var import_protobufjs = require("protobufjs");
var isOffchainSchemaAValidUrl = (offchainSchema) => {
return typeof offchainSchema === "string" && validateURLSafe(offchainSchema, "offchainSchema") && offchainSchema.indexOf("{id}") >= 0;
};
var decodeOldSchemaCollection = async (collectionId, properties, options) => {
const { imageUrlTemplate, dummyImageFullUrl } = options;
const propObj = properties.reduce((acc, { key, value }) => {
acc[key] = value;
return acc;
}, {});
const offchainSchema = propObj._old_offchainSchema;
const constOnchainSchema = propObj._old_constOnChainSchema;
const schemaVersion = propObj._old_schemaVersion;
const variableOnchainSchema = propObj._old_variableOnChainSchema;
const offchainSchemaIsValidUrl = isOffchainSchemaAValidUrl(offchainSchema);
const schema = {
schemaName: "_old_" /* old */,
collectionId,
coverPicture: {
url: dummyImageFullUrl,
fullUrl: null
},
image: {
urlTemplate: offchainSchemaIsValidUrl ? offchainSchema.replace("{id}", "{infix}") : imageUrlTemplate
},
schemaVersion: "0.0.1",
attributesSchema: {},
attributesSchemaVersion: "1.0.0"
};
let parsedVariableOnchainSchema = null;
try {
parsedVariableOnchainSchema = JSON.parse(variableOnchainSchema);
} catch {
}
if (parsedVariableOnchainSchema && typeof parsedVariableOnchainSchema === "object" && typeof parsedVariableOnchainSchema.collectionCover === "string") {
schema.coverPicture.ipfsCid = parsedVariableOnchainSchema.collectionCover;
delete schema.coverPicture.url;
schema.coverPicture.fullUrl = imageUrlTemplate.replace("{infix}", parsedVariableOnchainSchema.collectionCover);
} else if (offchainSchemaIsValidUrl) {
const coverUrl = offchainSchema.replace("{id}", "1");
schema.coverPicture.url = coverUrl;
schema.coverPicture.fullUrl = coverUrl;
}
let root = {};
let NFTMeta = {};
try {
root = import_protobufjs.Root.fromJSON(JSON.parse(constOnchainSchema));
NFTMeta = root.lookupType("onChainMetaData.NFTMeta");
} catch (err) {
return {
result: null,
error: err
};
}
const attributesSchema = {};
let i = 0;
for (const field of NFTMeta.fieldsArray) {
if (field.name === "ipfsJson") {
continue;
}
const options2 = !["string", "number"].includes(field.type) && root.lookupEnum(field.type).options;
const parsedOptions = options2 ? getValues(options2).map((v) => safeJSONParse(v)).filter((v) => typeof v !== "string" && typeof v.en === "string").map((v) => {
const result = { ...v };
if (typeof result._ === "string")
return result;
result._ = result.en || result[getKeys(result)[0]] || void 0;
if (typeof result._ !== "string")
return null;
return result;
}).filter((v) => !!v) : [];
const attr = {
type: "string" /* string */,
name: { _: field.name },
isArray: field.repeated,
optional: !field.required
};
if (parsedOptions.length) {
attr.enumValues = parsedOptions.reduce((acc, el, index) => {
acc[index] = el;
return acc;
}, {});
}
attributesSchema[i++] = attr;
}
schema.attributesSchema = attributesSchema;
schema.attributesSchemaVersion = "1.0.0";
schema.oldProperties = {
_old_schemaVersion: schemaVersion,
_old_offchainSchema: offchainSchema,
_old_constOnChainSchema: constOnchainSchema,
_old_variableOnChainSchema: variableOnchainSchema
};
return { result: schema, error: null };
};
var decodeOldSchemaToken = async (collectionId, tokenId, rawToken, schema, options) => {
const constOnchainSchema = schema.oldProperties?._old_constOnChainSchema;
if (!constOnchainSchema) {
return {
result: null,
error: new ValidationError(`collection doesn't contain _old_constOnChainSchema field`)
};
}
let root = {};
let NFTMeta = {};
try {
root = import_protobufjs.Root.fromJSON(JSON.parse(constOnchainSchema));
NFTMeta = root.lookupType("onChainMetaData.NFTMeta");
} catch (err) {
return {
result: null,
error: err
};
}
if (!rawToken) {
return {
result: null,
error: new ValidationError(`parsing token with old schema: no token passed`)
};
}
const parsedToken = {
owner: rawToken.owner.toHuman(),
properties: rawToken.properties.map((property) => {
return {
key: property.key.toHuman(),
value: property.value.toJSON()
};
})
};
const constDataProp = parsedToken.properties.find(({ key }) => key === "_old_constData");
if (!constDataProp) {
return {
result: null,
error: new ValidationError("no _old_constData property found")
};
}
const u8aToken = StringUtils.hexToU8a(constDataProp.value);
let tokenDecoded = {};
let tokenDecodedHuman = {};
try {
tokenDecoded = NFTMeta.decode(u8aToken);
tokenDecodedHuman = tokenDecoded.toJSON();
} catch (err) {
return {
result: null,
error: err
};
}
const tokenAttributesResult = {};
const entries = getEntries(tokenDecodedHuman);
let i = 0;
for (const entry of entries) {
let [name, rawValue] = entry;
if (name === "ipfsJson") {
continue;
}
let value = rawValue;
let isArray = false;
let isEnum = false;
const field = tokenDecoded.$type.fields[name];
if (!["string", "number"].includes(field.type)) {
const enumOptions = root.lookupEnum(field.type).options;
isEnum = !!enumOptions;
if (field.rule === "repeated" && Array.isArray(rawValue)) {
const parsedValues = rawValue.map((v) => {
const parsed = safeJSONParse(enumOptions?.[v] || v);
if (typeof parsed !== "string") {
parsed._ = parsed.en;
return parsed;
} else {
return null;
}
}).filter((v) => typeof v?._ === "string");
value = parsedValues;
isArray = true;
} else {
value = safeJSONParse(enumOptions?.[rawValue] || rawValue);
if (typeof value !== "string") {
value._ = value.en || getValues(value)[0];
}
}
}
if (field.type === "string")
value = { _: value };
tokenAttributesResult[i++] = {
name: { _: name },
type: field.type === "number" ? "float" /* float */ : "string" /* string */,
value,
isArray,
isEnum,
rawValue
};
}
const schemaVersion = schema.oldProperties?._old_schemaVersion;
const offchainSchema = schema.oldProperties?._old_offchainSchema;
const { imageUrlTemplate, dummyImageFullUrl } = options;
let image = {
url: dummyImageFullUrl,
fullUrl: null
};
let ipfsImageIsSet = false;
if (schemaVersion === "Unique") {
try {
const ipfsCid = JSON.parse(tokenDecodedHuman.ipfsJson).ipfs;
image = {
ipfsCid,
fullUrl: imageUrlTemplate.replace("{infix}", ipfsCid)
};
ipfsImageIsSet = true;
} catch {
}
}
if (!ipfsImageIsSet && isOffchainSchemaAValidUrl(offchainSchema)) {
image = {
urlInfix: tokenId.toString(),
fullUrl: offchainSchema.replace("{id}", tokenId.toString())
};
}
const decodedToken = {
collectionId,
tokenId,
owner: parsedToken.owner,
image,
attributes: tokenAttributesResult
};
if (parsedToken.owner.Ethereum && UniqueUtils.Address.is.nestingAddress(parsedToken.owner.Ethereum)) {
decodedToken.nestingParentToken = UniqueUtils.Address.nesting.addressToIds(parsedToken.owner.Ethereum);
}
return {
result: decodedToken,
error: null
};
};
// src/schema/tools/universal.ts
var universal_exports = {};
__export(universal_exports, {
universallyDecodeCollectionSchema: () => universallyDecodeCollectionSchema,
universallyDecodeToken: () => universallyDecodeToken
});
var DEFAULT_IMAGE_URL_TEMPLATE = `https://ipfs.unique.network/ipfs/{infix}`;
var DEFAULT_DUMMY_IMAGE_FULL_URL = `https://ipfs.unique.network/ipfs/QmPCqY7Lmxerm8cLKmB18kT1RxkwnpasPVksA8XLhViVT7`;
var parseImageLinkOptions = (options) => {
let imageUrlTemplate = DEFAULT_IMAGE_URL_TEMPLATE;
if (validateUrlTemplateStringSafe(options?.imageUrlTemplate, "options.imageUrlTemplate")) {
imageUrlTemplate = options.imageUrlTemplate;
}
const dummyImageFullUrl = typeof options?.dummyImageFullUrl === "string" ? options.dummyImageFullUrl : DEFAULT_DUMMY_IMAGE_FULL_URL;
return {
imageUrlTemplate,
dummyImageFullUrl
};
};
var universallyDecodeCollectionSchema = async (collectionId, properties, options) => {
const schemaNameProp = properties.find(({ key }) => key === "schemaName")?.value || null;
const schemaName = typeof schemaNameProp === "string" ? safeJsonParseStringOrHexString(schemaNameProp) : null;
const isOldSchema = !!properties.find(({ key }) => key === "_old_schemaVersion");
if (isOldSchema) {
const imageLinkOptions = parseImageLinkOptions(options);
return await decodeOldSchemaCollection(collectionId, properties, imageLinkOptions);
} else if (schemaName === "unique" /* unique */) {
return await decodeUniqueCollectionFromProperties(collectionId, properties);
}
return {
result: null,
error: new ValidationError(`Unknown collection schema`)
};
};
var universallyDecodeToken = async (collectionId, tokenId, rawToken, schema, options) => {
if (!schema) {
return {
result: null,
error: new ValidationError("unable to parse: collection schema was not provided")
};
}
const humanizedToken = rawToken.toHuman();
if (schema.schemaName === "unique" /* unique */) {
return await decodeTokenFromProperties(collectionId, tokenId, humanizedToken, schema);
} else if (schema.schemaName === "_old_" /* old */) {
const imageLinkOptions = parseImageLinkOptions(options);
return await decodeOldSchemaToken(collectionId, tokenId, rawToken, schema, imageLinkOptions);
}
return {
result: null,
error: new ValidationError(`unable to parse: collection schemaName is unknown (passed ${schema.schemaName}`)
};
};
// src/schema/index.ts
var SchemaTools = {
decode: {
collectionSchema: universallyDecodeCollectionSchema,
token: universallyDecodeToken
},
encodeUnique: {
collectionSchema: encodeCollectionSchemaToProperties,
collectionTokenPropertyPermissions: generateTokenPropertyPermissionsFromCollectionSchema,
token: encodeTokenToProperties
},
tools: {
unique: {
collection: collection_exports,
token: token_exports,
validators: validators_exports
},
oldSchema: oldSchemaDecoder_exports,
universal: universal_exports
},
types: types_exports
};
// src/substrate/SubstrateUnique.ts
var parseProperties = (rawProperties) => {
return rawProperties.map((property) => {
return {
key: StringUtils.hexStringToString(property.key),
value: StringUtils.hexStringToString(property.value)
};
});
};
var parseTokenPropertyPermissions = (tokenPropertyPermissions) => {
if (!Array.isArray(tokenPropertyPermissions)) {
return [];
}
return tokenPropertyPermissions.map((tpp) => {
return {
key: StringUtils.hexStringToString(tpp.key),
permission: tpp.permission
};
});
};
var SubstrateUnique = class extends SubstrateCommon {
async getBalance(address) {
const substrateAddress = address_exports.to.substrateNormalizedOrMirrorIfEthereum(address);
return await super.getBalance(substrateAddress);
}
async getCollection(collectionId, options) {
const superRawCollection = await this.api.rpc.unique.collectionById(collectionId);
if (!superRawCollection) {
return null;
}
const rawCollection = superRawCollection.toJSON();
const collection2 = {
id: collectionId,
collectionId,
owner: rawCollection.owner,
ownerNormalized: address_exports.normalize.substrateAddress(rawCollection.owner),
mode: rawCollection.mode,
name: StringUtils.vec2str(rawCollection.name),
description: StringUtils.vec2str(rawCollection.description),
tokenPrefix: StringUtils.hexStringToString(rawCollection.tokenPrefix),
sponsorship: rawCollection.sponsorship,
limits: rawCollection.limits,
permissions: rawCollection.permissions,
tokenPropertyPermissions: parseTokenPropertyPermissions(rawCollection.tokenPropertyPermissions),
properties: parseProperties(rawCollection.properties || []),
readOnly: rawCollection.readOnly,
effectiveLimits: null,
adminList: [],
lastTokenId: null,
uniqueSchema: null,
uniqueSchemaDecodingError: null,
get raw() {
return superRawCollection;
},
get human() {
return superRawCollection.toHuman();
}
};
const uniqueSchema = await SchemaTools.decode.collectionSchema(collectionId, collection2.properties);
collection2.uniqueSchema = uniqueSchema.result;
collection2.uniqueSchemaDecodingError = uniqueSchema.error;
if (options?.fetchAll || options?.fetchEffectiveLimits) {
collection2.effectiveLimits = (await this.api.rpc.unique.effectiveCollectionLimits(collectionId)).toHuman();
}
if (options?.fetchAll || options?.fetchAdmins) {
collection2.adminList = (await this.api.rpc.unique.adminlist(collectionId)).toHuman();
}
if (options?.fetchAll || options?.fetchNextTokenId) {
collection2.lastTokenId = (await this.api.rpc.unique.lastTokenId(collectionId)).toNumber();
}
return collection2;
}
async getToken(collectionId, tokenId, options) {
const superRawToken = await this.api.rpc.unique.tokenData(collectionId, tokenId);
if (!superRawToken || !superRawToken.owner)
return null;
const rawToken = superRawToken.toJSON();
const owner = address_exports.extract.crossAccountIdFromObject(rawToken.owner);
const ownerNormalized = address_exports.extract.crossAccountIdFromObjectNormalized(rawToken.owner);
const uniqueToken = options?.uniqueSchema ? await SchemaTools.decode.token(collectionId, tokenId, superRawToken, options?.uniqueSchema) : { result: null, error: new ValidationError("token parsing: no schema passed") };
const token = {
collectionId,
tokenId,
owner,
ownerNormalized,
properties: parseProperties(rawToken.properties),
uniqueToken: uniqueToken.result,
uniqueTokenDecodingError: uniqueToken.error,
get raw() {
return superRawToken;
},
get human() {
return superRawToken.toHuman();
}
};
return token;
}
transferCoins(params, options) {
const toAddress = address_exports.to.substrateNormalizedOrMirrorIfEthereum(params.toAddress);
return super.transferCoins({ ...params, toAddress }, options);
}
createCollection(params, options) {
return new ExtrinsicCreateCollection(this.api, params, options);
}
addCollectionAdmin(params, options) {
return new ExtrinsicAddCollectionAdmin(this.api, params, options);
}
removeCollectionAdmin(params, options) {
return new ExtrinsicRemoveCollectionAdmin(this.api, params, options);
}
setCollectionSponsor(params, options) {
return new ExtrinsicSetCollectionSponsor(this.api, params, options);
}
confirmSponsorship(params, options) {
return new ExtrinsicConfirmSponsorship(this.api, params, options);
}
changeCollectionOwner(params, options) {
return new ExtrinsicChangeCollectionOwner(this.api, params, options);
}
removeCollectionSponsor(params, options) {
return new ExtrinsicRemoveCollectionSponsor(this.api, params, options);
}
addToAllowList(params, options) {
return new ExtrinsicAddToAllowList(this.api, params, options);
}
removeFromAllowList(params, options) {
return new ExtrinsicRemoveFromAllowList(this.api, params, options);
}
createNftToken(params, options) {
return new ExtrinsicCreateNftToken(this.api, params, options);
}
createMultipleNftTokens(params, options) {
return new ExtrinsicCreateMultipleNftTokens(this.api, params, options);
}
};
// src/substrate/index.ts
var Substrate = {
Common: SubstrateCommon,
Unique: SubstrateUnique,
signer: signerTools_exports,
extension: extensionTools_exports2,
tools: {
extrinsic: extrinsicTools_exports
}
};
// src/index.ts
var init2 = init;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AttributeType,
AttributeTypeValues,
COLLECTION_SCHEMA_NAME,
Ethereum,
IntegerAttributeTypes,
NumberAttributeTypes,
SchemaTools,
StringAttributeTypes,
Substrate,
URL_TEMPLATE_INFIX,
UniqueUtils,
WS_RPC,
coins,
constants,
init,
libs
});
//# sourceMappingURL=index.js.map