UNPKG

@unique-nft/api

Version:

Definitely typed JS API for the Unique Network blockchain

2,640 lines 95.6 kB
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