UNPKG

@iota/iota-names-sdk

Version:
421 lines (420 loc) 15.6 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var iota_names_client_exports = {}; __export(iota_names_client_exports, { IotaNamesClient: () => IotaNamesClient }); module.exports = __toCommonJS(iota_names_client_exports); var import_bcs = require("@iota/iota-sdk/bcs"); var import__ = require("@iota/iota-sdk/graphql/schemas/2025.2"); var import_utils = require("@iota/iota-sdk/utils"); var import_blake2 = require("@noble/hashes/blake2"); var import_utils2 = require("@noble/hashes/utils"); var import_bcs2 = require("./bcs.js"); var import_constants = require("./constants.js"); var import_coupons = require("./coupons.js"); var import_helpers = require("./helpers.js"); var import_utils3 = require("./utils.js"); class IotaNamesClient { constructor(config) { this.graphQlClient = config.graphQlClient; if ("network" in config) { this.config = import_constants.packages[config.network]; } else { this.config = config.packageInfo; } } /** * Returns the core config of IOTA Names. */ async getCoreConfig() { if (!this.config.iotaNamesObjectId) throw new Error("IotaNames object ID is not set"); if (!this.config.packageId) throw new Error("IotaNames package ID is not set"); const coreConfigBcsB64 = (0, import_utils.toB64)( import_bcs2.DummyFieldBcs.serialize({ dummy_field: false }).toBytes() ); const coreConfigResponse = await this.graphQlClient.query({ query: (0, import__.graphql)(` query getCoreConfig($parentId: IotaAddress!, $name: DynamicFieldName!) { owner(address: $parentId) { address dynamicField(name: $name) { value { ... on MoveValue { json } } } } } `), variables: { parentId: this.config.iotaNamesObjectId, name: { type: (0, import_helpers.getConfigType)( this.config.packageId, (0, import_helpers.getCoreConfigType)(this.config.packageId) ), bcs: coreConfigBcsB64 } } }); const coreConfig = coreConfigResponse?.data?.owner?.dynamicField?.value?.json; if (!coreConfig) { throw new Error("Core config not found or is invalid"); } return coreConfig; } /** * Returns the price list for IOTA names in the base asset. */ // Format: // { // [ 3, 3 ] => 500000000, // [ 4, 4 ] => 100000000, // [ 5, 63 ] => 20000000 // } async getPriceList() { if (!this.config.iotaNamesObjectId) throw new Error("IotaNames object ID is not set"); if (!this.config.packageId) throw new Error("IotaNames package ID is not set"); const pricingConfigBcsB64 = (0, import_utils.toB64)( import_bcs2.DummyFieldBcs.serialize({ dummy_field: false }).toBytes() ); const priceListResponse = await this.graphQlClient.query({ query: (0, import__.graphql)(` query getPriceList($parentId: IotaAddress!, $name: DynamicFieldName!) { owner(address: $parentId) { address dynamicField(name: $name) { value { ... on MoveValue { json } } } } } `), variables: { parentId: this.config.iotaNamesObjectId, name: { type: (0, import_helpers.getConfigType)( this.config.packageId, (0, import_helpers.getPricelistConfigType)(this.config.packageId) ), bcs: pricingConfigBcsB64 } } }); const priceList = priceListResponse?.data?.owner?.dynamicField?.value?.json?.pricing; const contents = priceList?.contents; if (!contents) { throw new Error("Price list not found or content is invalid"); } const priceMap = /* @__PURE__ */ new Map(); for (const entry of contents) { const { pos0, pos1 } = entry.key; const key = [Number(pos0), Number(pos1)]; const value = Number(entry.value); priceMap.set(key, value); } return priceMap; } /** * Returns the renewal price list for IOTA names in the base asset. */ // Format: // { // [ 3, 3 ] => 500000000, // [ 4, 4 ] => 100000000, // [ 5, 63 ] => 20000000 // } async getRenewalPriceList() { if (!this.config.iotaNamesObjectId) throw new Error("IotaNames object ID is not set"); if (!this.config.packageId) throw new Error("IotaNames package ID is not set"); const pricingConfigBcsB64 = (0, import_utils.toB64)( import_bcs2.DummyFieldBcs.serialize({ dummy_field: false }).toBytes() ); const priceListResponse = await this.graphQlClient.query({ query: (0, import__.graphql)(` query getRenewalPriceList($parentId: IotaAddress!, $name: DynamicFieldName!) { owner(address: $parentId) { address dynamicField(name: $name) { value { ... on MoveValue { json } } } } } `), variables: { parentId: this.config.iotaNamesObjectId, name: { type: (0, import_helpers.getConfigType)( this.config.packageId, (0, import_helpers.getRenewalPricelistConfigType)(this.config.packageId) ), bcs: pricingConfigBcsB64 } } }); const priceList = priceListResponse?.data?.owner?.dynamicField?.value?.json?.config?.pricing; const contents = priceList?.contents; if (!contents) { throw new Error("Price list not found or content is invalid"); } const priceMap = /* @__PURE__ */ new Map(); for (const entry of contents) { const { pos0, pos1 } = entry.key; const key = [Number(pos0), Number(pos1)]; const value = Number(entry.value); priceMap.set(key, value); } return priceMap; } async getDefaultName(address) { const response = await this.graphQlClient.query({ query: (0, import__.graphql)(` query resolveNameServiceName($address: IotaAddress!, $nameFormat: NameFormat) { address(address: $address) { iotaNamesDefaultName(format: $nameFormat) } } `), variables: { address } }); const defaultName = response?.data?.address?.iotaNamesDefaultName ?? null; return defaultName; } async getNameRecord(name) { if (!(0, import_utils3.isValidIotaName)(name)) throw new Error("Invalid IOTA name"); if (!this.config.registryTableId) throw new Error("IotaNames package ID is not set"); const nameBcsB64 = (0, import_utils.toB64)( import_bcs2.NameBcs.serialize({ labels: (0, import_utils3.normalizeIotaName)(name, "dot").split(".").reverse() }).toBytes() ); const nameRecordResponse = await this.graphQlClient.query({ query: (0, import__.graphql)(` query getNameRecord($parentId: IotaAddress!, $name: DynamicFieldName!) { owner(address: $parentId) { address dynamicField(name: $name) { value { ... on MoveValue { json } } } } } `), variables: { parentId: this.config.registryTableId, name: { type: (0, import_helpers.getNameType)(this.config.packageId), bcs: nameBcsB64 } } }); const nameRecord = nameRecordResponse.data?.owner?.dynamicField?.value?.json; if (!nameRecord) return null; const nameRecordData = nameRecord.data?.contents; if (nameRecord.error || !nameRecordData) throw new Error("Name record not found. This name is not registered."); const data = {}; if (nameRecordData) { nameRecordData.forEach((field) => { if (field.key) { data[field.key] = field.value; } }); } return { name, nftId: nameRecord?.nft_id, targetAddress: nameRecord?.target_address, expirationTimestampMs: Number(nameRecord?.expiration_timestamp_ms), data, avatar: data[import_constants.ALLOWED_METADATA.avatar] }; } async getCouponHouse() { if (!this.config.iotaNamesObjectId) throw new Error("IotaNames object ID is not set"); if (!this.config.packageId) throw new Error("IotaNames package ID is not set"); if (!this.config.couponsPackageId) throw new Error("Coupon package ID is not set"); const iotaNamesObjectId = this.config.iotaNamesObjectId; const packageId = this.config.packageId; const couponsPackageId = this.config.couponsPackageId; const DummyFieldB64 = import_bcs2.DummyFieldBcs.serialize({ dummy_field: false }).toBase64(); const couponHouseResponse = await this.graphQlClient.query({ query: (0, import__.graphql)(` query getIotaNamesCouponHouseRegistryKey( $parentId: IotaAddress! $name: DynamicFieldName! ) { owner(address: $parentId) { dynamicField(name: $name) { value { ... on MoveValue { bcs } } } } } `), variables: { parentId: iotaNamesObjectId, name: { type: `${packageId}::iota_names::RegistryKey<${couponsPackageId}::coupon_house::CouponHouse>`, bcs: DummyFieldB64 } } }); const couponsHouseDynamicFieldBcsValue = couponHouseResponse?.data?.owner?.dynamicField?.value?.bcs; if (!couponsHouseDynamicFieldBcsValue) { throw new Error("Coupon house not found or is invalid"); } return import_bcs2.CouponHouseBcs.parse((0, import_utils.fromB64)(couponsHouseDynamicFieldBcsValue)); } async resolveCoupon(couponCode) { const couponHouse = await this.getCouponHouse(); const couponsTableId = couponHouse?.coupons?.coupons?.id.id.bytes; if (!couponsTableId) { throw new Error("Coupons table ID not found in the coupon house"); } const couponCodeHash = (0, import_utils2.bytesToHex)((0, import_blake2.blake2b)(couponCode, { dkLen: 32 })); const couponCodeBytes = (0, import_utils2.hexToBytes)(couponCodeHash); const couponCodeB64 = import_bcs.bcs.vector(import_bcs.bcs.u8()).serialize(couponCodeBytes).toBase64(); const couponResponse = await this.graphQlClient.query({ query: (0, import__.graphql)(` query getCouponBcs($parentId: IotaAddress!, $name: DynamicFieldName!) { owner(address: $parentId) { dynamicField(name: $name) { value { ... on MoveValue { bcs } } } } } `), variables: { parentId: couponsTableId, name: { type: "vector<u8>", bcs: couponCodeB64 } } }); const couponBcsBase64 = couponResponse?.data?.owner?.dynamicField?.value?.bcs; if (!couponBcsBase64) { return null; } const couponData = import_bcs2.CouponBcs.parse((0, import_utils.fromB64)(couponBcsBase64)); return { ...couponData, couponCode }; } /** * Calculates the registration or renewal price for an SLN (Second Level Name). * It expects a name, the number of years and a `IotaNamesPriceList` object, * as returned from `iotaNamesClient.getPriceList()` function, or `iotaNames.getRenewalPriceList()` function. * * It throws an error: * 1. if the name is a subname * 2. if the name is not a valid IOTA name * 3. if the years are not between 1 and 5 */ async calculatePrice({ name, years, isRegistration = true }) { if (!(0, import_utils3.isValidIotaName)(name)) { throw new Error("Invalid IOTA names"); } (0, import_helpers.validateYears)(years); if ((0, import_helpers.isSubname)(name)) { throw new Error("Subnames do not have a registration fee"); } const length = (0, import_utils3.normalizeIotaName)(name, "dot").split(".")[0].length; const priceList = await this.getPriceList(); const renewalPriceList = await this.getRenewalPriceList(); let yearsRemain = years; let price = 0; if (isRegistration) { for (const [[minLength, maxLength], pricePerYear] of priceList.entries()) { if (length >= minLength && length <= maxLength) { price += pricePerYear; yearsRemain -= 1; break; } } } for (const [[minLength, maxLength], pricePerYear] of renewalPriceList.entries()) { if (length >= minLength && length <= maxLength) { price += yearsRemain * pricePerYear; break; } } return price; } async calculateDiscountedPrice({ coupons, name, years, isRegistration = true, address }) { if (coupons.every((coupon) => typeof coupon === "string")) { const couponPromises = coupons.map(async (couponCode) => { const coupon = await this.resolveCoupon(couponCode); if (!coupon) { throw new Error(`Coupon not found: ${couponCode}`); } return coupon; }); coupons = await Promise.all(couponPromises); } const normalizedName = (0, import_utils3.normalizeIotaName)(name, "dot"); (0, import_utils3.validateIotaName)(normalizedName); const nameParts = normalizedName.split("."); const firstNamePart = nameParts[0]; (0, import_coupons.validateCoupons)(coupons, years, firstNamePart.length, address); const standardPrice = await this.calculatePrice({ name, years, isRegistration }); return (0, import_coupons.applyCouponsToPrice)(coupons, standardPrice); } } //# sourceMappingURL=iota-names-client.js.map