UNPKG

@mysten/suins

Version:
384 lines (382 loc) 15.1 kB
import { ALLOWED_METADATA, MAX_U64 } from "./constants.mjs"; import { isNestedSubName, isSubName, zeroCoin } from "./helpers.mjs"; import { calculatePrice, calculatePriceAfterDiscount, handleBasePayment, handlePayment } from "./contracts/suins_payments/payments.mjs"; import { initRegistration, initRenewal, register, renew } from "./contracts/suins/payment.mjs"; import { burnExpired, burnExpiredSubname, setReverseLookup } from "./contracts/suins/controller.mjs"; import { applyCoupon } from "./contracts/suins_coupons/coupon_house.mjs"; import { applyPercentageDiscount } from "./contracts/suins_discounts/discounts.mjs"; import { freeClaim } from "./contracts/suins_discounts/free_claims.mjs"; import { SUI_CLOCK_OBJECT_ID, isValidSuiNSName, normalizeSuiNSName } from "@mysten/sui/utils"; import { bcs } from "@mysten/sui/bcs"; //#region src/suins-transaction.ts var SuinsTransaction = class { constructor(client, transaction) { this.suinsClient = client; this.transaction = transaction; } /** * Registers a domain for a number of years. */ register(params) { if (params.couponCode && params.discountInfo) throw new Error("Cannot apply both coupon and discount NFT"); const paymentIntent = this.initRegistration(params.domain); if (params.couponCode) this.applyCoupon(paymentIntent, params.couponCode); if (params.discountInfo) this.applyDiscount(paymentIntent, params.discountInfo); const priceAfterDiscount = this.calculatePriceAfterDiscount(paymentIntent, params.coinConfig.type); const receipt = this.generateReceipt({ paymentIntent, priceAfterDiscount, coinConfig: params.coinConfig, coin: params.coin, maxAmount: params.maxAmount, priceInfoObjectId: params.priceInfoObjectId }); const nft = this.finalizeRegister(receipt); if (params.years > 1) this.renew({ nft, years: params.years - 1, coinConfig: params.coinConfig, coin: params.coin, couponCode: params.couponCode, discountInfo: params.discountInfo, maxAmount: params.maxAmount, priceInfoObjectId: params.priceInfoObjectId }); return nft; } /** * Renews an NFT for a number of years. */ renew(params) { if (params.couponCode && params.discountInfo) throw new Error("Cannot apply both coupon and discount NFT"); const paymentIntent = this.initRenewal(params.nft, params.years); if (params.couponCode) this.applyCoupon(paymentIntent, params.couponCode); if (params.discountInfo) this.applyDiscount(paymentIntent, params.discountInfo); const priceAfterDiscount = this.calculatePriceAfterDiscount(paymentIntent, params.coinConfig.type); const receipt = this.generateReceipt({ paymentIntent, priceAfterDiscount, coinConfig: params.coinConfig, coin: params.coin, maxAmount: params.maxAmount, priceInfoObjectId: params.priceInfoObjectId }); this.finalizeRenew(receipt, params.nft); } initRegistration(domain) { const config = this.suinsClient.config; return this.transaction.add(initRegistration({ package: config.packageId, arguments: { suins: config.suins, domain } })); } initRenewal(nft, years) { const config = this.suinsClient.config; return this.transaction.add(initRenewal({ package: config.packageId, arguments: { suins: config.suins, nft: this.transaction.object(nft), years } })); } calculatePrice(baseAmount, paymentType, priceInfoObjectId) { const config = this.suinsClient.config; return this.transaction.add(calculatePrice({ package: config.payments.packageId, arguments: { suins: config.suins, baseAmount, priceInfoObject: priceInfoObjectId }, typeArguments: [paymentType] })); } handleBasePayment(paymentIntent, paymentArg, paymentType) { const config = this.suinsClient.config; return this.transaction.add(handleBasePayment({ package: config.payments.packageId, arguments: { suins: config.suins, bbbVault: config.bbb.vault, intent: paymentIntent, payment: paymentArg }, typeArguments: [paymentType] })); } handlePayment(paymentIntent, paymentArg, paymentType, priceInfoObjectId, maxAmount = MAX_U64) { const config = this.suinsClient.config; return this.transaction.add(handlePayment({ package: config.payments.packageId, arguments: { suins: config.suins, bbbVault: config.bbb.vault, intent: paymentIntent, payment: paymentArg, priceInfoObject: priceInfoObjectId, userPriceGuard: maxAmount }, typeArguments: [paymentType] })); } finalizeRegister(receipt) { const config = this.suinsClient.config; return this.transaction.add(register({ package: config.packageId, arguments: { receipt, suins: config.suins } })); } finalizeRenew(receipt, nft) { const config = this.suinsClient.config; return this.transaction.add(renew({ package: config.packageId, arguments: { receipt, suins: config.suins, nft: this.transaction.object(nft) } })); } calculatePriceAfterDiscount(paymentIntent, paymentType) { const config = this.suinsClient.config; return this.transaction.add(calculatePriceAfterDiscount({ package: config.payments.packageId, arguments: { suins: config.suins, intent: paymentIntent }, typeArguments: [paymentType] })); } generateReceipt(params) { if (params.coinConfig.feed === "") { const payment = params.coin ? this.transaction.splitCoins(this.transaction.object(params.coin), [params.priceAfterDiscount]) : zeroCoin(this.transaction, params.coinConfig.type); return this.handleBasePayment(params.paymentIntent, payment, params.coinConfig.type); } else { const priceInfoObjectId = params.priceInfoObjectId; if (!priceInfoObjectId) throw new Error("Price info object ID is required for non-base asset purchases"); const price = this.calculatePrice(params.priceAfterDiscount, params.coinConfig.type, priceInfoObjectId); if (!params.coin) throw new Error("coin input is required"); const payment = this.transaction.splitCoins(this.transaction.object(params.coin), [price]); return this.handlePayment(params.paymentIntent, payment, params.coinConfig.type, priceInfoObjectId, params.maxAmount); } } /** * Applies a coupon to the payment intent. */ applyCoupon(intent, couponCode) { const config = this.suinsClient.config; return this.transaction.add(applyCoupon({ package: config.coupons.packageId, arguments: { suins: config.suins, intent, couponCode } })); } /** * Applies a discount to the payment intent. */ applyDiscount(intent, discountInfo) { const config = this.suinsClient.config; if (discountInfo.isFreeClaim) this.transaction.add(freeClaim({ package: config.discountsPackage.packageId, arguments: { self: config.discountsPackage.discountHouseId, suins: config.suins, intent, object: this.transaction.object(discountInfo.discountNft) }, typeArguments: [discountInfo.type] })); else this.transaction.add(applyPercentageDiscount({ package: config.discountsPackage.packageId, arguments: { self: config.discountsPackage.discountHouseId, intent, suins: config.suins, _: this.transaction.object(discountInfo.discountNft) }, typeArguments: [discountInfo.type] })); } /** * Creates a subdomain. */ createSubName({ parentNft, name, expirationTimestampMs, allowChildCreation, allowTimeExtension }) { if (!isValidSuiNSName(name)) throw new Error("Invalid SuiNS name"); const isParentSubdomain = isNestedSubName(name); if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (!this.suinsClient.config.subNamesPackageId) throw new Error("Subnames package ID not found"); if (isParentSubdomain && !this.suinsClient.config.tempSubdomainsProxyPackageId) throw new Error("Subnames proxy package ID not found"); return this.transaction.moveCall({ target: isParentSubdomain ? `${this.suinsClient.config.tempSubdomainsProxyPackageId}::subdomain_proxy::new` : `${this.suinsClient.config.subNamesPackageId}::subdomains::new`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(parentNft), this.transaction.object(SUI_CLOCK_OBJECT_ID), this.transaction.pure.string(normalizeSuiNSName(name, "dot")), this.transaction.pure.u64(expirationTimestampMs), this.transaction.pure.bool(!!allowChildCreation), this.transaction.pure.bool(!!allowTimeExtension) ] }); } /** * Builds the PTB to create a leaf subdomain. * Parent can be a `SuinsRegistration` or a `SubDomainRegistration` object. * Can be passed in as an ID or a TransactionArgument. */ createLeafSubName({ parentNft, name, targetAddress }) { if (!isValidSuiNSName(name)) throw new Error("Invalid SuiNS name"); const isParentSubdomain = isNestedSubName(name); if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (!this.suinsClient.config.subNamesPackageId) throw new Error("Subnames package ID not found"); if (isParentSubdomain && !this.suinsClient.config.tempSubdomainsProxyPackageId) throw new Error("Subnames proxy package ID not found"); this.transaction.moveCall({ target: isParentSubdomain ? `${this.suinsClient.config.tempSubdomainsProxyPackageId}::subdomain_proxy::new_leaf` : `${this.suinsClient.config.subNamesPackageId}::subdomains::new_leaf`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(parentNft), this.transaction.object(SUI_CLOCK_OBJECT_ID), this.transaction.pure.string(normalizeSuiNSName(name, "dot")), this.transaction.pure.address(targetAddress) ] }); } /** * Removes a leaf subname. */ removeLeafSubName({ parentNft, name }) { if (!isValidSuiNSName(name)) throw new Error("Invalid SuiNS name"); const isParentSubdomain = isNestedSubName(name); if (!isSubName(name)) throw new Error("This can only be invoked for subnames"); if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (!this.suinsClient.config.subNamesPackageId) throw new Error("Subnames package ID not found"); if (isParentSubdomain && !this.suinsClient.config.tempSubdomainsProxyPackageId) throw new Error("Subnames proxy package ID not found"); this.transaction.moveCall({ target: isParentSubdomain ? `${this.suinsClient.config.tempSubdomainsProxyPackageId}::subdomain_proxy::remove_leaf` : `${this.suinsClient.config.subNamesPackageId}::subdomains::remove_leaf`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(parentNft), this.transaction.object(SUI_CLOCK_OBJECT_ID), this.transaction.pure.string(normalizeSuiNSName(name, "dot")) ] }); } /** * Sets the target address of an NFT. */ setTargetAddress({ nft, address, isSubname }) { if (isSubname && !this.suinsClient.config.tempSubdomainsProxyPackageId) throw new Error("Subnames proxy package ID not found"); this.transaction.moveCall({ target: isSubname ? `${this.suinsClient.config.tempSubdomainsProxyPackageId}::subdomain_proxy::set_target_address` : `${this.suinsClient.config.packageId}::controller::set_target_address`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(nft), this.transaction.pure(bcs.option(bcs.Address).serialize(address).toBytes()), this.transaction.object(SUI_CLOCK_OBJECT_ID) ] }); } /** * Sets a default name for the user. */ setDefault(name) { if (!isValidSuiNSName(name)) throw new Error("Invalid SuiNS name"); if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); this.transaction.add(setReverseLookup({ package: this.suinsClient.config.packageId, arguments: { suins: this.suinsClient.config.suins, domainName: normalizeSuiNSName(name, "dot") } })); } /** * Edits the setup of a subname. */ editSetup({ parentNft, name, allowChildCreation, allowTimeExtension }) { if (!isValidSuiNSName(name)) throw new Error("Invalid SuiNS name"); const isParentSubdomain = isNestedSubName(name); if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (!isParentSubdomain && !this.suinsClient.config.subNamesPackageId) throw new Error("Subnames package ID not found"); if (isParentSubdomain && !this.suinsClient.config.tempSubdomainsProxyPackageId) throw new Error("Subnames proxy package ID not found"); this.transaction.moveCall({ target: isParentSubdomain ? `${this.suinsClient.config.tempSubdomainsProxyPackageId}::subdomain_proxy::edit_setup` : `${this.suinsClient.config.subNamesPackageId}::subdomains::edit_setup`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(parentNft), this.transaction.object(SUI_CLOCK_OBJECT_ID), this.transaction.pure.string(normalizeSuiNSName(name, "dot")), this.transaction.pure.bool(!!allowChildCreation), this.transaction.pure.bool(!!allowTimeExtension) ] }); } /** * Extends the expiration of a subname. */ extendExpiration({ nft, expirationTimestampMs }) { if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (!this.suinsClient.config.subNamesPackageId) throw new Error("Subnames package ID not found"); this.transaction.moveCall({ target: `${this.suinsClient.config.subNamesPackageId}::subdomains::extend_expiration`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(nft), this.transaction.pure.u64(expirationTimestampMs) ] }); } /** * Sets the user data of an NFT. */ setUserData({ nft, value, key, isSubname }) { if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (isSubname && !this.suinsClient.config.tempSubdomainsProxyPackageId) throw new Error("Subnames proxy package ID not found"); if (!Object.values(ALLOWED_METADATA).some((x) => x === key)) throw new Error("Invalid key"); this.transaction.moveCall({ target: isSubname ? `${this.suinsClient.config.tempSubdomainsProxyPackageId}::subdomain_proxy::set_user_data` : `${this.suinsClient.config.packageId}::controller::set_user_data`, arguments: [ this.transaction.object(this.suinsClient.config.suins), this.transaction.object(nft), this.transaction.pure.string(key), this.transaction.pure.string(value), this.transaction.object(SUI_CLOCK_OBJECT_ID) ] }); } /** * Burns an expired NFT to collect storage rebates. */ burnExpired({ nft, isSubname }) { if (!this.suinsClient.config.suins) throw new Error("SuiNS Object ID not found"); if (isSubname) this.transaction.add(burnExpiredSubname({ package: this.suinsClient.config.packageId, arguments: { suins: this.suinsClient.config.suins, nft: this.transaction.object(nft) } })); else this.transaction.add(burnExpired({ package: this.suinsClient.config.packageId, arguments: { suins: this.suinsClient.config.suins, nft: this.transaction.object(nft) } })); } }; //#endregion export { SuinsTransaction }; //# sourceMappingURL=suins-transaction.mjs.map