@thenamespace/ens-components 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import * as zlib from 'zlib';
4
4
  import * as crypto$5 from 'crypto';
5
5
  import * as net from 'net';
6
6
  import * as viem from 'viem';
7
- import { ContractFunctionExecutionError, parseAbi, namehash as namehash$1, encodeFunctionData, toHex, toBytes as toBytes$1, pad, isAddress as isAddress$1, keccak256, formatEther, zeroAddress, zeroHash } from 'viem';
7
+ import { ContractFunctionExecutionError, parseAbi, namehash as namehash$1, encodeFunctionData, toHex, toBytes as toBytes$1, pad, isAddress as isAddress$1, keccak256, parseEther, padHex, formatEther, zeroAddress, concatHex, zeroHash } from 'viem';
8
8
  import * as chains$1 from 'viem/chains';
9
9
  import { baseSepolia, sepolia, mainnet, optimism, base as base$3, zoraSepolia, zora, celoAlfajores, celo, polygonMumbai, polygon, arbitrumSepolia, arbitrum, optimismSepolia } from 'viem/chains';
10
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -11642,6 +11642,50 @@ const wait = (ms) => {
11642
11642
  return new Promise((resolve) => setTimeout(resolve, ms));
11643
11643
  };
11644
11644
 
11645
+ const ONE_DAY = 86400;
11646
+ const ONE_YEAR = 365 * ONE_DAY;
11647
+ const MIN_REGISTRATION_SECONDS = 28 * ONE_DAY;
11648
+ const secondsToDateInput = (expirySeconds) => {
11649
+ const date = new Date(expirySeconds * 1e3);
11650
+ const year = date.getFullYear();
11651
+ const month = String(date.getMonth() + 1).padStart(2, "0");
11652
+ const day = String(date.getDate()).padStart(2, "0");
11653
+ return `${year}-${month}-${day}`;
11654
+ };
11655
+ const roundDurationWithDay = (valueAsDate, nowSeconds) => {
11656
+ const start = new Date(nowSeconds * 1e3);
11657
+ const endDay = Date.UTC(valueAsDate.getFullYear(), valueAsDate.getMonth(), valueAsDate.getDate());
11658
+ const startDay = Date.UTC(start.getFullYear(), start.getMonth(), start.getDate());
11659
+ const days = Math.floor((endDay - startDay) / 864e5);
11660
+ return Math.max(0, days * 86400);
11661
+ };
11662
+ const secondsFromYears = (startDate, years) => {
11663
+ const end = new Date(startDate.getTime());
11664
+ end.setFullYear(end.getFullYear() + years);
11665
+ return Math.floor((end.getTime() - startDate.getTime()) / 1e3);
11666
+ };
11667
+ const yearsFromSeconds = (seconds) => seconds / ONE_YEAR;
11668
+ const formatDurationSummary = (durationSeconds) => {
11669
+ const now = /* @__PURE__ */ new Date();
11670
+ const end = new Date(now.getTime() + durationSeconds * 1e3);
11671
+ let years = end.getFullYear() - now.getFullYear();
11672
+ let months = end.getMonth() - now.getMonth();
11673
+ let days = end.getDate() - now.getDate();
11674
+ if (days < 0) {
11675
+ months -= 1;
11676
+ days += new Date(end.getFullYear(), end.getMonth(), 0).getDate();
11677
+ }
11678
+ if (months < 0) {
11679
+ years -= 1;
11680
+ months += 12;
11681
+ }
11682
+ const parts = [];
11683
+ if (years > 0) parts.push(`${years} year${years !== 1 ? "s" : ""}`);
11684
+ if (months > 0) parts.push(`${months} month${months !== 1 ? "s" : ""}`);
11685
+ if (days > 0 && years === 0) parts.push(`${days} day${days !== 1 ? "s" : ""}`);
11686
+ return parts.slice(0, 2).join(", ") || "0 days";
11687
+ };
11688
+
11645
11689
  const isValidEmvAddress = (value) => {
11646
11690
  return isAddress$1(value);
11647
11691
  };
@@ -11855,6 +11899,124 @@ function ProgressBar({ progress }) {
11855
11899
  ) }) });
11856
11900
  }
11857
11901
 
11902
+ const CalendarSVG = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: 16, height: 16, fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M19 3h-1V1h-2v2H8V1H6v2H5C3.9 3 3 3.9 3 5v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z" }) });
11903
+ const DurationPicker = ({
11904
+ durationSeconds,
11905
+ onDurationChange,
11906
+ minSeconds = MIN_REGISTRATION_SECONDS
11907
+ }) => {
11908
+ const [durationType, setDurationType] = useState("years");
11909
+ const dateInputRef = useRef(null);
11910
+ const nowSecondsRef = useRef(Math.floor(Date.now() / 1e3));
11911
+ const nowSeconds = nowSecondsRef.current;
11912
+ const years = Math.max(1, Math.floor(yearsFromSeconds(durationSeconds)));
11913
+ const minusSeconds = secondsFromYears(/* @__PURE__ */ new Date(), years - 1);
11914
+ const handleMinusYear = () => {
11915
+ if (minusSeconds >= minSeconds) {
11916
+ onDurationChange(minusSeconds);
11917
+ }
11918
+ };
11919
+ const handlePlusYear = () => {
11920
+ onDurationChange(secondsFromYears(/* @__PURE__ */ new Date(), years + 1));
11921
+ };
11922
+ const handleDateChange = (e) => {
11923
+ const { valueAsDate } = e.currentTarget;
11924
+ if (!valueAsDate) return;
11925
+ const normalised = new Date(
11926
+ valueAsDate.getTime() + valueAsDate.getTimezoneOffset() * 60 * 1e3
11927
+ );
11928
+ const minDate = new Date((nowSeconds + minSeconds) * 1e3);
11929
+ const clamped = normalised < minDate ? minDate : normalised;
11930
+ onDurationChange(roundDurationWithDay(clamped, nowSeconds));
11931
+ };
11932
+ const handleToggleMode = () => {
11933
+ if (durationType === "years") {
11934
+ setDurationType("date");
11935
+ } else {
11936
+ const snapped = secondsFromYears(
11937
+ /* @__PURE__ */ new Date(),
11938
+ Math.max(1, Math.floor(yearsFromSeconds(durationSeconds)))
11939
+ );
11940
+ onDurationChange(snapped);
11941
+ setDurationType("years");
11942
+ }
11943
+ };
11944
+ const minusDisabled = minusSeconds < minSeconds;
11945
+ const expirySeconds = nowSeconds + durationSeconds;
11946
+ const expiryDateDisplay = new Date(expirySeconds * 1e3).toLocaleDateString("en-US", {
11947
+ month: "long",
11948
+ day: "numeric",
11949
+ year: "numeric"
11950
+ });
11951
+ return /* @__PURE__ */ jsxs("div", { className: "ns-duration-picker", children: [
11952
+ durationType === "years" ? /* @__PURE__ */ jsxs("div", { className: "ns-duration-picker__control", children: [
11953
+ /* @__PURE__ */ jsx(
11954
+ Button,
11955
+ {
11956
+ className: "ns-duration-picker__btn",
11957
+ onClick: handleMinusYear,
11958
+ disabled: minusDisabled,
11959
+ children: "\u2212"
11960
+ }
11961
+ ),
11962
+ /* @__PURE__ */ jsxs("span", { className: "ns-duration-picker__label", children: [
11963
+ years,
11964
+ " year",
11965
+ years !== 1 ? "s" : ""
11966
+ ] }),
11967
+ /* @__PURE__ */ jsx(
11968
+ Button,
11969
+ {
11970
+ className: "ns-duration-picker__btn ns-duration-picker__btn--plus",
11971
+ onClick: handlePlusYear,
11972
+ children: "+"
11973
+ }
11974
+ )
11975
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "ns-duration-picker__calendar", children: [
11976
+ /* @__PURE__ */ jsx("span", { className: "ns-duration-picker__date-display", children: expiryDateDisplay }),
11977
+ /* @__PURE__ */ jsx(
11978
+ "input",
11979
+ {
11980
+ ref: dateInputRef,
11981
+ type: "date",
11982
+ className: "ns-duration-picker__date-input",
11983
+ value: secondsToDateInput(expirySeconds),
11984
+ min: secondsToDateInput(nowSeconds + minSeconds),
11985
+ onChange: handleDateChange
11986
+ }
11987
+ ),
11988
+ /* @__PURE__ */ jsx(
11989
+ "button",
11990
+ {
11991
+ type: "button",
11992
+ className: "ns-duration-picker__calendar-btn",
11993
+ onClick: () => dateInputRef.current?.showPicker?.(),
11994
+ "aria-label": "Open calendar",
11995
+ children: /* @__PURE__ */ jsx(CalendarSVG, {})
11996
+ }
11997
+ )
11998
+ ] }),
11999
+ /* @__PURE__ */ jsxs("div", { className: "ns-duration-picker__footer", children: [
12000
+ /* @__PURE__ */ jsxs(Text, { size: "xs", color: "grey", children: [
12001
+ formatDurationSummary(durationSeconds),
12002
+ " registration.\xA0"
12003
+ ] }),
12004
+ /* @__PURE__ */ jsxs(
12005
+ "button",
12006
+ {
12007
+ type: "button",
12008
+ className: "ns-duration-picker__toggle",
12009
+ onClick: handleToggleMode,
12010
+ children: [
12011
+ "Pick by ",
12012
+ durationType === "years" ? "date" : "years"
12013
+ ]
12014
+ }
12015
+ )
12016
+ ] })
12017
+ ] });
12018
+ };
12019
+
11858
12020
  const PricingDisplay = ({
11859
12021
  primaryFee,
11860
12022
  networkFees,
@@ -11868,42 +12030,31 @@ const PricingDisplay = ({
11868
12030
  if (!ethUsdRate || totalLoading || total.amount === "Free" || total.amount === "N/A") {
11869
12031
  return null;
11870
12032
  }
11871
- const eth = parseFloat(String(total.amount));
12033
+ const eth = parseFloat(String(total.amount).replace(/^~/, ""));
11872
12034
  if (isNaN(eth) || eth <= 0) return null;
11873
12035
  return (eth * ethUsdRate).toFixed(2);
11874
12036
  }, [ethUsdRate, total.amount, totalLoading]);
11875
12037
  return /* @__PURE__ */ jsxs("div", { className: `ens-registration-pricing ${className}`, children: [
11876
- expiryPicker && /* @__PURE__ */ jsxs("div", { className: "ens-expiry-picker d-flex justify-content-between mb-2", children: [
11877
- /* @__PURE__ */ jsx(
11878
- Button,
11879
- {
11880
- disabled: expiryPicker.years <= 1,
11881
- onClick: () => expiryPicker.onYearsChange(expiryPicker.years - 1),
11882
- children: "-"
11883
- }
11884
- ),
11885
- /* @__PURE__ */ jsxs(Text, { children: [
11886
- expiryPicker.years,
11887
- " year",
11888
- expiryPicker.years > 1 ? "s" : ""
11889
- ] }),
11890
- /* @__PURE__ */ jsx(Button, { onClick: () => expiryPicker.onYearsChange(expiryPicker.years + 1), children: "+" })
11891
- ] }),
12038
+ expiryPicker && /* @__PURE__ */ jsx("div", { className: "ens-expiry-picker mb-2", children: /* @__PURE__ */ jsx(
12039
+ DurationPicker,
12040
+ {
12041
+ durationSeconds: expiryPicker.durationSeconds,
12042
+ onDurationChange: expiryPicker.onDurationChange,
12043
+ minSeconds: expiryPicker.minSeconds
12044
+ }
12045
+ ) }),
11892
12046
  /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-between align-items-center mb-1", children: [
11893
12047
  /* @__PURE__ */ jsx(Text, { size: "sm", color: "grey", children: primaryFee.label }),
11894
- primaryFee.isChecking ? /* @__PURE__ */ jsx(ShurikenSpinner, { size: 16 }) : /* @__PURE__ */ jsx(Text, { size: "sm", color: "grey", children: primaryFee.amount === "Free" ? "Free" : `${primaryFee.amount} ETH` })
12048
+ primaryFee.isChecking ? /* @__PURE__ */ jsx(ShurikenSpinner, { size: 16 }) : /* @__PURE__ */ jsx(Text, { size: "sm", color: "grey", children: primaryFee.amount === "Free" || primaryFee.amount === "N/A" ? primaryFee.amount : `${primaryFee.amount} ETH` })
11895
12049
  ] }),
11896
12050
  networkFees && /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-between align-items-center mb-1", children: [
11897
12051
  /* @__PURE__ */ jsx(Text, { size: "sm", color: "grey", children: "Est. network fees" }),
11898
- networkFees.isChecking ? /* @__PURE__ */ jsx(ShurikenSpinner, { size: 16 }) : /* @__PURE__ */ jsxs(Text, { size: "sm", color: "grey", children: [
11899
- networkFees.amount,
11900
- " ETH"
11901
- ] })
12052
+ networkFees.isChecking ? /* @__PURE__ */ jsx(ShurikenSpinner, { size: 16 }) : /* @__PURE__ */ jsx(Text, { size: "sm", color: "grey", children: networkFees.amount === "N/A" ? "N/A" : `${networkFees.amount} ETH` })
11902
12053
  ] }),
11903
12054
  /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-between align-items-center mt-2 total-fee", children: [
11904
12055
  /* @__PURE__ */ jsx(Text, { size: "lg", weight: "bold", children: "Total" }),
11905
12056
  totalLoading ? /* @__PURE__ */ jsx(ShurikenSpinner, { size: 20 }) : /* @__PURE__ */ jsxs("div", { style: { textAlign: "right" }, children: [
11906
- /* @__PURE__ */ jsx(Text, { size: "lg", weight: "bold", children: total.amount === "Free" ? "Free" : `${total.amount} ETH` }),
12057
+ /* @__PURE__ */ jsx(Text, { size: "lg", weight: "bold", children: total.amount === "Free" || total.amount === "N/A" ? total.amount : `${total.amount} ETH` }),
11907
12058
  totalUsd && /* @__PURE__ */ jsxs(Text, { size: "xs", color: "grey", children: [
11908
12059
  "\u2248 $",
11909
12060
  totalUsd
@@ -63982,7 +64133,18 @@ const ABIS = {
63982
64133
  RESOLVER
63983
64134
  };
63984
64135
 
63985
- const SECONDS_IN_YEAR = 31536e3;
64136
+ const COMMITMENTS_SLOT = 1n;
64137
+ const FIVE_MINUTES_SECONDS = 5 * 60;
64138
+ const HEURISTIC_COMMIT_GAS = 50000n;
64139
+ const HEURISTIC_REGISTER_BASE_GAS = 240000n;
64140
+ const HEURISTIC_GAS_PER_RECORD = 50000n;
64141
+ const isStateOverrideRejection = (err) => {
64142
+ const e = err;
64143
+ const code = e?.code ?? e?.cause?.code;
64144
+ if (code === -32602 || code === -32601 || code === -32e3) return true;
64145
+ const msg = `${e?.shortMessage ?? ""} ${e?.message ?? ""}`.toLowerCase();
64146
+ return msg.includes("state override") || msg.includes("stateoverride") || msg.includes("too many arguments") || msg.includes("invalid argument 2") || msg.includes("3rd parameter") || msg.includes("does not support");
64147
+ };
63986
64148
  const NAMESPACE_REFERRER_ADDRESS = "0xb7B18611b8C51B4B3F400BaF09DB49E61e0aF044";
63987
64149
  const ENS_REGISTRY_ABI = parseAbi([
63988
64150
  "function owner(bytes32) view returns (address)"
@@ -63995,12 +64157,12 @@ const useRegisterENS = ({ isTestnet }) => {
63995
64157
  const { data: walletClient } = useWalletClient({
63996
64158
  chainId: isTestnet ? sepolia.id : mainnet.id
63997
64159
  });
63998
- const getRegistrationPrice = async (label, expiryInYears = 1) => {
64160
+ const getRegistrationPrice = async (label, durationInSeconds = ONE_YEAR) => {
63999
64161
  const ethController = getEthController();
64000
64162
  const price = await publicClient.readContract({
64001
64163
  abi: ABIS.ETH_REGISTRAR_CONTOLLER,
64002
64164
  functionName: "rentPrice",
64003
- args: [label, BigInt(expiryInYears * SECONDS_IN_YEAR)],
64165
+ args: [label, BigInt(durationInSeconds)],
64004
64166
  address: ethController,
64005
64167
  account: address
64006
64168
  });
@@ -64025,7 +64187,7 @@ const useRegisterENS = ({ isTestnet }) => {
64025
64187
  const c = {
64026
64188
  label: request.label,
64027
64189
  owner: request.owner,
64028
- duration: BigInt(yearsToSeconds(request.expiryInYears)),
64190
+ duration: BigInt(request.durationInSeconds),
64029
64191
  secret: keccak256(toBytes$1(request.secret)),
64030
64192
  resolver: getPublicResolver(),
64031
64193
  data: resolverData,
@@ -64039,9 +64201,6 @@ const useRegisterENS = ({ isTestnet }) => {
64039
64201
  args: [c]
64040
64202
  });
64041
64203
  };
64042
- const yearsToSeconds = (years) => {
64043
- return Math.ceil(years * SECONDS_IN_YEAR);
64044
- };
64045
64204
  const sendCommitmentTx = async (request) => {
64046
64205
  if (!walletClient || !walletClient.account) {
64047
64206
  throw new Error("Wallet client is not available");
@@ -64065,17 +64224,14 @@ const useRegisterENS = ({ isTestnet }) => {
64065
64224
  const registration = {
64066
64225
  label: request.label,
64067
64226
  owner: request.owner,
64068
- duration: BigInt(yearsToSeconds(request.expiryInYears)),
64227
+ duration: BigInt(request.durationInSeconds),
64069
64228
  secret: keccak256(toBytes$1(request.secret)),
64070
64229
  resolver: getPublicResolver(),
64071
64230
  data: resolverData,
64072
64231
  reverseRecord: 0,
64073
64232
  referrer: getRegReferrer(request)
64074
64233
  };
64075
- const price = await getRegistrationPrice(
64076
- request.label,
64077
- request.expiryInYears
64078
- );
64234
+ const price = await getRegistrationPrice(request.label, request.durationInSeconds);
64079
64235
  const { request: contractRequest } = await publicClient.simulateContract({
64080
64236
  address: getEthController(),
64081
64237
  abi: ABIS.ETH_REGISTRAR_CONTOLLER,
@@ -64085,20 +64241,92 @@ const useRegisterENS = ({ isTestnet }) => {
64085
64241
  value: price.wei
64086
64242
  });
64087
64243
  const tx = await walletClient.writeContract(contractRequest);
64244
+ return { txHash: tx, price };
64245
+ };
64246
+ const getEffectiveGasPrice = () => publicClient.getGasPrice();
64247
+ const commitmentStorageSlot = (commitment) => keccak256(
64248
+ concatHex([padHex(commitment, { size: 32 }), padHex(toHex(COMMITMENTS_SLOT), { size: 32 })])
64249
+ );
64250
+ const estimateRegistrationFees = async (request) => {
64251
+ const fullName = `${request.label}.eth`;
64252
+ const resolverData = convertToResolverData(fullName, request.records);
64253
+ const controller = getEthController();
64254
+ const commitmentParams = {
64255
+ label: request.label,
64256
+ owner: request.owner,
64257
+ duration: BigInt(request.durationInSeconds),
64258
+ secret: keccak256(toBytes$1(request.secret)),
64259
+ resolver: getPublicResolver(),
64260
+ data: resolverData,
64261
+ reverseRecord: 0,
64262
+ referrer: getRegReferrer(request)
64263
+ };
64264
+ const commitment = await publicClient.readContract({
64265
+ functionName: "makeCommitment",
64266
+ abi: ABIS.ETH_REGISTRAR_CONTOLLER,
64267
+ address: controller,
64268
+ args: [commitmentParams]
64269
+ });
64270
+ const price = await getRegistrationPrice(request.label, request.durationInSeconds);
64271
+ const fiveMinAgo = BigInt(Math.floor(Date.now() / 1e3) - FIVE_MINUTES_SECONDS);
64272
+ const balanceOverride = price.wei * 2n + parseEther("1000000");
64273
+ const gasPricePromise = getEffectiveGasPrice();
64274
+ const commitGasPromise = publicClient.estimateContractGas({
64275
+ address: controller,
64276
+ abi: ABIS.ETH_REGISTRAR_CONTOLLER,
64277
+ functionName: "commit",
64278
+ args: [commitment],
64279
+ account: request.owner
64280
+ }).catch(() => HEURISTIC_COMMIT_GAS);
64281
+ const registerGasPromise = publicClient.estimateContractGas({
64282
+ address: controller,
64283
+ abi: ABIS.ETH_REGISTRAR_CONTOLLER,
64284
+ functionName: "register",
64285
+ args: [commitmentParams],
64286
+ account: request.owner,
64287
+ value: price.wei,
64288
+ stateOverride: [
64289
+ {
64290
+ address: controller,
64291
+ stateDiff: [
64292
+ {
64293
+ slot: commitmentStorageSlot(commitment),
64294
+ value: padHex(toHex(fiveMinAgo), { size: 32 })
64295
+ }
64296
+ ]
64297
+ },
64298
+ { address: request.owner, balance: balanceOverride }
64299
+ ]
64300
+ }).then((g) => ({ gas: g, isHeuristic: false })).catch((err) => {
64301
+ if (typeof console !== "undefined") {
64302
+ console.warn(
64303
+ "[useRegisterENS] register-gas estimation failed; using heuristic.",
64304
+ isStateOverrideRejection(err) ? "(state override unsupported)" : "",
64305
+ err
64306
+ );
64307
+ }
64308
+ const recordCount = (request.records.addresses?.length ?? 0) + (request.records.texts?.length ?? 0);
64309
+ const heuristic = HEURISTIC_REGISTER_BASE_GAS + BigInt(recordCount) * HEURISTIC_GAS_PER_RECORD;
64310
+ return { gas: heuristic, isHeuristic: true };
64311
+ });
64312
+ const [commitGas, registerResult, gasPrice] = await Promise.all([
64313
+ commitGasPromise,
64314
+ registerGasPromise,
64315
+ gasPricePromise
64316
+ ]);
64317
+ const totalGas = commitGas + registerResult.gas;
64318
+ const totalWei = totalGas * gasPrice;
64088
64319
  return {
64089
- txHash: tx,
64090
- price
64320
+ wei: totalWei,
64321
+ eth: parseFloat(formatEther(totalWei)),
64322
+ gasEstimate: totalGas,
64323
+ gasPrice,
64324
+ isHeuristic: registerResult.isHeuristic
64091
64325
  };
64092
64326
  };
64093
- const getEthController = () => {
64094
- return distExports$1.getEnsContracts(isTestnet).ethRegistrarController;
64095
- };
64096
- const getEnsRegistry = () => {
64097
- return distExports$1.getEnsContracts(isTestnet).ensRegistry;
64098
- };
64099
- const getPublicResolver = () => {
64100
- return distExports$1.getEnsContracts(isTestnet).publicResolver;
64101
- };
64327
+ const getEthController = () => distExports$1.getEnsContracts(isTestnet).ethRegistrarController;
64328
+ const getEnsRegistry = () => distExports$1.getEnsContracts(isTestnet).ensRegistry;
64329
+ const getPublicResolver = () => distExports$1.getEnsContracts(isTestnet).publicResolver;
64102
64330
  const getRegReferrer = (request) => {
64103
64331
  const referrerAddress = request.referrer && isAddress$1(request.referrer) ? request.referrer : NAMESPACE_REFERRER_ADDRESS;
64104
64332
  return createEnsReferer(referrerAddress);
@@ -64106,6 +64334,7 @@ const useRegisterENS = ({ isTestnet }) => {
64106
64334
  return {
64107
64335
  isEnsAvailable,
64108
64336
  getRegistrationPrice,
64337
+ estimateRegistrationFees,
64109
64338
  sendCommitmentTx,
64110
64339
  sendRegisterTx
64111
64340
  };
@@ -89328,7 +89557,7 @@ var img$1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAvQAAAGjCAYAAABDv4HEA
89328
89557
  const MIN_ENS_LEN$2 = 3;
89329
89558
  const RegistrationSummary = ({
89330
89559
  label,
89331
- years,
89560
+ durationSeconds,
89332
89561
  price,
89333
89562
  nameValidation,
89334
89563
  transactionFees,
@@ -89339,7 +89568,7 @@ const RegistrationSummary = ({
89339
89568
  hideBanner = false,
89340
89569
  bannerWidth = 250,
89341
89570
  onLabelChange,
89342
- onYearsChange,
89571
+ onDurationChange,
89343
89572
  onPriceChange,
89344
89573
  onNameValidationChange,
89345
89574
  onSetProfile,
@@ -89348,33 +89577,21 @@ const RegistrationSummary = ({
89348
89577
  }) => {
89349
89578
  const { isConnected } = useAccount();
89350
89579
  const { ethUsdRate } = useEthDollarValue();
89351
- const { isEnsAvailable, getRegistrationPrice } = useRegisterENS({
89352
- isTestnet
89353
- });
89580
+ const { isEnsAvailable, getRegistrationPrice } = useRegisterENS({ isTestnet });
89354
89581
  const { regPrice, regFees, regTotal } = useMemo(() => {
89355
- let regPrice2 = 0;
89356
- let regFees2 = 0;
89357
- let total = 0;
89358
- if (price) {
89359
- regPrice2 += price.eth;
89360
- total += price.eth;
89361
- }
89362
- if (transactionFees) {
89363
- regFees2 += transactionFees.price.eth;
89364
- total += transactionFees.price.eth;
89365
- }
89366
- return {
89367
- regFees: regFees2,
89368
- regPrice: regPrice2,
89369
- regTotal: formatFloat(total, 5)
89370
- };
89582
+ const priceEth = price?.eth ?? 0;
89583
+ const feesEth = transactionFees?.price.eth ?? 0;
89584
+ const heuristicPrefix = transactionFees?.isHeuristic ? "~" : "";
89585
+ const regPrice2 = priceEth > 0 ? priceEth.toFixed(4) : "0.0000";
89586
+ const regFees2 = transactionFees?.failed ? "N/A" : `${heuristicPrefix}${feesEth.toFixed(4)}`;
89587
+ const regTotal2 = transactionFees?.failed ? "N/A" : `${heuristicPrefix}${(priceEth + feesEth).toFixed(4)}`;
89588
+ return { regPrice: regPrice2, regFees: regFees2, regTotal: regTotal2 };
89371
89589
  }, [price, transactionFees]);
89372
89590
  const checkAvailability = async (labelToCheck) => {
89373
- let _available = false;
89374
89591
  try {
89375
- _available = await isEnsAvailable(labelToCheck);
89376
- onNameValidationChange({ isChecking: false, isTaken: !_available });
89377
- } catch (err) {
89592
+ const available = await isEnsAvailable(labelToCheck);
89593
+ onNameValidationChange({ isChecking: false, isTaken: !available });
89594
+ } catch {
89378
89595
  onNameValidationChange({
89379
89596
  isChecking: false,
89380
89597
  isTaken: false,
@@ -89382,20 +89599,12 @@ const RegistrationSummary = ({
89382
89599
  });
89383
89600
  }
89384
89601
  };
89385
- const checkRegistrationPrice = async (labelToCheck, expiry) => {
89602
+ const checkRegistrationPrice = async (labelToCheck, durationSecs) => {
89386
89603
  try {
89387
- const rentPrice = await getRegistrationPrice(labelToCheck, expiry);
89388
- onPriceChange({
89389
- isChecking: false,
89390
- eth: rentPrice.eth,
89391
- wei: rentPrice.wei
89392
- });
89393
- } catch (err) {
89394
- onPriceChange({
89395
- isChecking: false,
89396
- eth: -1,
89397
- wei: 0n
89398
- });
89604
+ const rentPrice = await getRegistrationPrice(labelToCheck, durationSecs);
89605
+ onPriceChange({ isChecking: false, eth: rentPrice.eth, wei: rentPrice.wei });
89606
+ } catch {
89607
+ onPriceChange({ isChecking: false, eth: -1, wei: 0n });
89399
89608
  }
89400
89609
  };
89401
89610
  const debouncedCheckAvailability = useCallback(
@@ -89404,19 +89613,17 @@ const RegistrationSummary = ({
89404
89613
  );
89405
89614
  const debouncedCheckPrice = useCallback(
89406
89615
  debounce(
89407
- (labelToCheck, expiryYears) => checkRegistrationPrice(labelToCheck, expiryYears),
89616
+ (labelToCheck, durationSecs) => checkRegistrationPrice(labelToCheck, durationSecs),
89408
89617
  500
89409
89618
  ),
89410
89619
  []
89411
89620
  );
89412
89621
  const handleNameChanged = async (value) => {
89413
89622
  const _value = value.toLocaleLowerCase().trim();
89414
- if (_value.includes(".")) {
89415
- return;
89416
- }
89623
+ if (_value.includes(".")) return;
89417
89624
  try {
89418
89625
  normalize(_value);
89419
- } catch (err) {
89626
+ } catch {
89420
89627
  return;
89421
89628
  }
89422
89629
  onLabelChange(_value);
@@ -89424,22 +89631,21 @@ const RegistrationSummary = ({
89424
89631
  onNameValidationChange({ isChecking: true, isTaken: false });
89425
89632
  onPriceChange({ isChecking: true, eth: 0, wei: 0n });
89426
89633
  debouncedCheckAvailability(_value);
89427
- debouncedCheckPrice(_value, years);
89634
+ debouncedCheckPrice(_value, durationSeconds);
89428
89635
  } else {
89429
89636
  onNameValidationChange({ isChecking: false, isTaken: false });
89430
89637
  }
89431
89638
  };
89432
- const handleYearsChange = (newYears) => {
89433
- if (newYears < 1) {
89434
- return;
89435
- }
89639
+ const handleDurationChange = (newSeconds) => {
89640
+ if (newSeconds < MIN_REGISTRATION_SECONDS) return;
89436
89641
  onPriceChange({ ...price, isChecking: true });
89437
- onYearsChange(newYears);
89438
- debouncedCheckPrice(label, newYears);
89642
+ onDurationChange(newSeconds);
89643
+ debouncedCheckPrice(label, newSeconds);
89439
89644
  };
89440
- const isNameAvailable = useMemo(() => {
89441
- return label.length >= MIN_ENS_LEN$2 && !nameValidation.isChecking && !nameValidation.isTaken;
89442
- }, [label.length, nameValidation.isChecking, nameValidation.isTaken]);
89645
+ const isNameAvailable = useMemo(
89646
+ () => label.length >= MIN_ENS_LEN$2 && !nameValidation.isChecking && !nameValidation.isTaken,
89647
+ [label.length, nameValidation.isChecking, nameValidation.isTaken]
89648
+ );
89443
89649
  const nextBtnDisabled = label.length < MIN_ENS_LEN$2 || nameValidation.isChecking || nameValidation.isTaken;
89444
89650
  const totalPriceLoading = transactionFees?.isChecking || price.isChecking;
89445
89651
  const transactionFeesLoading = transactionFees?.isChecking || false;
@@ -89493,17 +89699,15 @@ const RegistrationSummary = ({
89493
89699
  amount: regPrice,
89494
89700
  isChecking: price.isChecking
89495
89701
  },
89496
- networkFees: {
89497
- amount: regFees,
89498
- isChecking: transactionFeesLoading
89499
- },
89702
+ networkFees: transactionFees ? { amount: regFees, isChecking: transactionFeesLoading } : void 0,
89500
89703
  total: {
89501
89704
  amount: regTotal,
89502
89705
  isChecking: totalPriceLoading
89503
89706
  },
89504
89707
  expiryPicker: {
89505
- years,
89506
- onYearsChange: handleYearsChange
89708
+ durationSeconds,
89709
+ onDurationChange: handleDurationChange,
89710
+ minSeconds: MIN_REGISTRATION_SECONDS
89507
89711
  },
89508
89712
  ethUsdRate
89509
89713
  }
@@ -89516,15 +89720,7 @@ const RegistrationSummary = ({
89516
89720
  style: { cursor: "pointer" },
89517
89721
  children: /* @__PURE__ */ jsxs("div", { className: "d-flex justify-content-between align-items-center", children: [
89518
89722
  /* @__PURE__ */ jsxs("div", { className: "d-flex align-items-center", children: [
89519
- /* @__PURE__ */ jsx("div", { className: "shuriken-cont d-flex align-items-center justify-content-center", children: /* @__PURE__ */ jsx(
89520
- "img",
89521
- {
89522
- className: "shuriken",
89523
- width: 50,
89524
- src: img$3,
89525
- alt: "shuricken"
89526
- }
89527
- ) }),
89723
+ /* @__PURE__ */ jsx("div", { className: "shuriken-cont d-flex align-items-center justify-content-center", children: /* @__PURE__ */ jsx("img", { className: "shuriken", width: 50, src: img$3, alt: "shuricken" }) }),
89528
89724
  /* @__PURE__ */ jsxs("div", { className: "ms-3", children: [
89529
89725
  /* @__PURE__ */ jsx(Text, { size: "sm", weight: "medium", children: "Complete your profile" }),
89530
89726
  /* @__PURE__ */ jsx(Text, { size: "xs", color: "grey", children: "Make your ENS more discoverable" })
@@ -89535,16 +89731,7 @@ const RegistrationSummary = ({
89535
89731
  }
89536
89732
  )
89537
89733
  ] }),
89538
- !isConnected && onConnectWallet ? /* @__PURE__ */ jsx(
89539
- Button,
89540
- {
89541
- style: { width: "100%" },
89542
- size: "lg",
89543
- className: "mt-2",
89544
- onClick: onConnectWallet,
89545
- children: "Connect Wallet"
89546
- }
89547
- ) : /* @__PURE__ */ jsx(
89734
+ !isConnected && onConnectWallet ? /* @__PURE__ */ jsx(Button, { style: { width: "100%" }, size: "lg", className: "mt-2", onClick: onConnectWallet, children: "Connect Wallet" }) : /* @__PURE__ */ jsx(
89548
89735
  Button,
89549
89736
  {
89550
89737
  style: { width: "100%" },
@@ -89708,11 +89895,11 @@ const CommitmentStep = ({
89708
89895
  setError(null);
89709
89896
  let tx = null;
89710
89897
  try {
89711
- setBtnState({ ...btnState, waitingWallet: true });
89898
+ setBtnState({ waitingWallet: true, waitingTx: false });
89712
89899
  const request = {
89713
89900
  label: state.label,
89714
89901
  owner: address,
89715
- expiryInYears: state.expiryInYears,
89902
+ durationInSeconds: state.durationInSeconds,
89716
89903
  secret: state.secret,
89717
89904
  records: state.records,
89718
89905
  referrer: state.referrer
@@ -89742,13 +89929,19 @@ const CommitmentStep = ({
89742
89929
  return;
89743
89930
  }
89744
89931
  try {
89745
- await waitTx({ hash: tx });
89932
+ const receipt = await waitTx({ hash: tx });
89933
+ const commitFeeWei = receipt.gasUsed * (receipt.effectiveGasPrice || 0n);
89746
89934
  setCommitTxStatus({ sent: true, completed: true, hash: tx });
89747
89935
  setTimeout(() => {
89748
89936
  onStateUpdated({
89749
89937
  ...state,
89750
89938
  step: ProcessSteps.TimerStarted,
89751
- commitment: { tx, completed: true, time: (/* @__PURE__ */ new Date()).getTime() }
89939
+ commitment: {
89940
+ tx,
89941
+ completed: true,
89942
+ time: (/* @__PURE__ */ new Date()).getTime(),
89943
+ feeWei: commitFeeWei
89944
+ }
89752
89945
  });
89753
89946
  setCommitTxStatus({ sent: false, completed: false, hash: "" });
89754
89947
  }, 1e3);
@@ -89922,33 +90115,22 @@ const RegistrationStep = ({
89922
90115
  onStateUpdated,
89923
90116
  onSuccess
89924
90117
  }) => {
89925
- const [btnState, setBtnState] = useState({
89926
- waitingTx: false,
89927
- waitingWallet: false
89928
- });
90118
+ const [btnState, setBtnState] = useState({ waitingWallet: false, waitingTx: false });
89929
90119
  const { address } = useAccount();
89930
90120
  const { waitTx } = useWaitTransaction({ isTestnet });
89931
- const [error, setError] = useState(
89932
- null
89933
- );
89934
- const [commitTxStatus, setCommitTxStatus] = useState({
89935
- sent: false,
89936
- completed: false,
89937
- hash: ""
89938
- });
89939
- const { sendRegisterTx, getRegistrationPrice } = useRegisterENS({
89940
- isTestnet
89941
- });
90121
+ const [error, setError] = useState(null);
90122
+ const [commitTxStatus, setCommitTxStatus] = useState({ sent: false, completed: false, hash: "" });
90123
+ const { sendRegisterTx } = useRegisterENS({ isTestnet });
89942
90124
  const handleRegistration = async () => {
89943
90125
  setError(null);
89944
90126
  let tx = null;
89945
90127
  let registrationPrice = 0;
89946
90128
  try {
89947
- setBtnState({ ...btnState, waitingWallet: true });
90129
+ setBtnState({ waitingWallet: true, waitingTx: false });
89948
90130
  const request = {
89949
90131
  label: state.label,
89950
90132
  owner: address,
89951
- expiryInYears: state.expiryInYears,
90133
+ durationInSeconds: state.durationInSeconds,
89952
90134
  secret: state.secret,
89953
90135
  records: state.records,
89954
90136
  referrer: state.referrer
@@ -89968,27 +90150,23 @@ const RegistrationStep = ({
89968
90150
  if (err instanceof ContractFunctionExecutionError && !isUserDeniedError(err)) {
89969
90151
  setError(err);
89970
90152
  } else if (!isUserDeniedError(err)) {
89971
- const genericError = new Error(
89972
- err?.shortMessage || err?.message || "Transaction failed"
90153
+ setError(
90154
+ new Error(err?.shortMessage || err?.message || "Transaction failed")
89973
90155
  );
89974
- setError(genericError);
89975
90156
  }
89976
90157
  } finally {
89977
90158
  setBtnState({ waitingTx: false, waitingWallet: false });
89978
90159
  }
89979
- if (!tx) {
89980
- return;
89981
- }
90160
+ if (!tx) return;
89982
90161
  try {
89983
90162
  const receipt = await waitTx({ hash: tx });
89984
90163
  setCommitTxStatus({ sent: true, completed: true, hash: tx });
89985
- const gasUsed = receipt.gasUsed;
89986
- const gasPrice = receipt.effectiveGasPrice || BigInt(0);
89987
- const transactionFees = gasUsed * gasPrice;
89988
- const transactionFeesEth = formatEther(transactionFees);
90164
+ const registerFeeWei = receipt.gasUsed * (receipt.effectiveGasPrice || 0n);
90165
+ const commitFeeWei = state.commitment?.feeWei ?? 0n;
90166
+ const totalFeeWei = registerFeeWei + commitFeeWei;
90167
+ const transactionFeesEth = formatEther(totalFeeWei);
89989
90168
  const totalCost = (registrationPrice + parseFloat(transactionFeesEth)).toString();
89990
- const expiryDate = /* @__PURE__ */ new Date();
89991
- expiryDate.setFullYear(expiryDate.getFullYear() + state.expiryInYears);
90169
+ const expiryDate = new Date(Date.now() + state.durationInSeconds * 1e3);
89992
90170
  const formattedExpiryDate = expiryDate.toLocaleDateString("en-US", {
89993
90171
  year: "numeric",
89994
90172
  month: "long",
@@ -89998,11 +90176,11 @@ const RegistrationStep = ({
89998
90176
  onStateUpdated({
89999
90177
  ...state,
90000
90178
  step: ProcessSteps.RegistrationCompleted,
90001
- commitment: { tx, completed: true, time: (/* @__PURE__ */ new Date()).getTime() }
90179
+ commitment: { tx, completed: true, time: Date.now() }
90002
90180
  });
90003
90181
  setCommitTxStatus({ sent: false, completed: false, hash: "" });
90004
90182
  onSuccess?.({
90005
- expiryInYears: state.expiryInYears,
90183
+ durationLabel: formatDurationSummary(state.durationInSeconds),
90006
90184
  registrationCost: registrationPrice.toString(),
90007
90185
  transactionFees: transactionFeesEth,
90008
90186
  total: totalCost,
@@ -90017,26 +90195,19 @@ const RegistrationStep = ({
90017
90195
  setCommitTxStatus({ sent: false, completed: false, hash: "" });
90018
90196
  }
90019
90197
  };
90020
- const { isCurrentStep, isDisabled, isPending, isCompleted } = useMemo(() => {
90021
- const isPending2 = state.step < ProcessSteps.TimerCompleted;
90198
+ const { isCurrentStep, isDisabled, isCompleted } = useMemo(() => {
90022
90199
  const isCurrentStep2 = state.step >= ProcessSteps.TimerCompleted && state.step < ProcessSteps.RegistrationCompleted;
90023
90200
  const isCompleted2 = state.step >= ProcessSteps.RegistrationCompleted;
90024
90201
  const isDisabled2 = state.step < ProcessSteps.TimerCompleted;
90025
- return {
90026
- isCurrentStep: isCurrentStep2,
90027
- isDisabled: isDisabled2,
90028
- isPending: isPending2,
90029
- isCompleted: isCompleted2
90030
- };
90202
+ return { isCurrentStep: isCurrentStep2, isDisabled: isDisabled2, isCompleted: isCompleted2 };
90031
90203
  }, [state]);
90032
90204
  const getProgressStatusBadge = () => {
90033
90205
  if (isCurrentStep) {
90034
90206
  return /* @__PURE__ */ jsx("div", { className: "ns-process-badge me-2", children: /* @__PURE__ */ jsx(Text, { color: "white", weight: "bold", size: "sm", children: "3" }) });
90035
90207
  } else if (isCompleted) {
90036
90208
  return /* @__PURE__ */ jsx("div", { className: "ns-process-badge ns-process-badge--inactive ns-process-badge--completed me-2", children: /* @__PURE__ */ jsx(Icon, { name: "check", size: 16, color: "black" }) });
90037
- } else {
90038
- return /* @__PURE__ */ jsx("div", { className: "ns-process-badge ns-process-badge--inactive me-2", children: /* @__PURE__ */ jsx(Text, { color: "primary", weight: "bold", size: "sm", children: "3" }) });
90039
90209
  }
90210
+ return /* @__PURE__ */ jsx("div", { className: "ns-process-badge ns-process-badge--inactive me-2", children: /* @__PURE__ */ jsx(Text, { color: "primary", weight: "bold", size: "sm", children: "3" }) });
90040
90211
  };
90041
90212
  const btnDisabled = btnState.waitingTx || btnState.waitingWallet;
90042
90213
  const btnLabel = btnState.waitingWallet ? "Waiting Wallet..." : "Open Wallet";
@@ -90054,15 +90225,7 @@ const RegistrationStep = ({
90054
90225
  !commitTxStatus.sent && /* @__PURE__ */ jsxs("div", { className: "ns-text-center", children: [
90055
90226
  /* @__PURE__ */ jsx(Text, { weight: "medium", className: "mb-2", children: "Register Name" }),
90056
90227
  /* @__PURE__ */ jsx(Text, { size: "xs", color: "grey", children: "Your name is not registered until you've completed the second transaction. You have 23 hours remaining to complete it." }),
90057
- /* @__PURE__ */ jsx(
90058
- Button,
90059
- {
90060
- disabled: btnDisabled,
90061
- onClick: () => handleRegistration(),
90062
- className: "mt-3 ns-wd-100",
90063
- children: btnLabel
90064
- }
90065
- ),
90228
+ /* @__PURE__ */ jsx(Button, { disabled: btnDisabled, onClick: handleRegistration, className: "mt-3 ns-wd-100", children: btnLabel }),
90066
90229
  /* @__PURE__ */ jsx(ContractErrorLabel, { error })
90067
90230
  ] }),
90068
90231
  commitTxStatus.sent && /* @__PURE__ */ jsx(
@@ -90727,7 +90890,7 @@ var img = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAALQAAACBCAYAAABpepAsAAA
90727
90890
 
90728
90891
  const SuccessScreen$1 = ({
90729
90892
  ensName,
90730
- expiryInYears,
90893
+ durationLabel,
90731
90894
  registrationCost,
90732
90895
  transactionFees,
90733
90896
  total,
@@ -90789,8 +90952,8 @@ const SuccessScreen$1 = ({
90789
90952
  /* @__PURE__ */ jsxs("div", { className: "ens-registration-success-summary", children: [
90790
90953
  /* @__PURE__ */ jsxs("div", { className: "ens-registration-success-summary-row", children: [
90791
90954
  /* @__PURE__ */ jsxs(Text, { size: "sm", color: "grey", children: [
90792
- expiryInYears,
90793
- " year registration"
90955
+ durationLabel,
90956
+ " registration"
90794
90957
  ] }),
90795
90958
  /* @__PURE__ */ jsxs(Text, { size: "sm", color: "grey", children: [
90796
90959
  parseFloat(registrationCost).toFixed(4),
@@ -90853,24 +91016,21 @@ const generateEnsRegistrationSecret = () => {
90853
91016
  return toHex(Math.floor(Math.random() * 1e9));
90854
91017
  };
90855
91018
 
90856
- const getBlankRegistrationState = (label, exiryInYears, records, isTestnet, referrer) => {
90857
- const blankRegistrationState = {
90858
- step: ProcessSteps.Start,
90859
- label,
90860
- commitment: { completed: false, time: 0 },
90861
- registration: { completed: false },
90862
- timerStartedAt: 0,
90863
- expiryInYears: exiryInYears,
90864
- secret: generateEnsRegistrationSecret(),
90865
- records,
90866
- isTestnet,
90867
- referrer
90868
- };
90869
- return blankRegistrationState;
90870
- };
91019
+ const getBlankRegistrationState = (label, durationInSeconds, records, isTestnet, referrer) => ({
91020
+ step: ProcessSteps.Start,
91021
+ label,
91022
+ commitment: { completed: false, time: 0 },
91023
+ registration: { completed: false },
91024
+ timerStartedAt: 0,
91025
+ durationInSeconds,
91026
+ secret: generateEnsRegistrationSecret(),
91027
+ records,
91028
+ isTestnet,
91029
+ referrer
91030
+ });
90871
91031
  const RegistrationProcess = ({
90872
91032
  label,
90873
- expiryInYears,
91033
+ durationInSeconds,
90874
91034
  isTestnet = false,
90875
91035
  records,
90876
91036
  onBack,
@@ -90884,29 +91044,17 @@ const RegistrationProcess = ({
90884
91044
  const isOnCorrectNetwork = chain?.id === expectedChainId;
90885
91045
  const shouldSwitchNetwork = chain && !isOnCorrectNetwork;
90886
91046
  const [registrationState, setRegistrationState] = useState(
90887
- getBlankRegistrationState(
90888
- label,
90889
- expiryInYears,
90890
- records,
90891
- isTestnet,
90892
- referrer
90893
- )
91047
+ () => getBlankRegistrationState(label, durationInSeconds, records, isTestnet, referrer)
90894
91048
  );
90895
91049
  const [showConfirmClose, setShowConfirmClose] = useState(false);
90896
91050
  useEffect(() => {
90897
- setRegistrationState({ ...registrationState, records });
91051
+ setRegistrationState((prev) => ({ ...prev, records }));
90898
91052
  }, [records]);
90899
91053
  const handleSwitchNetwork = () => {
90900
- if (switchChain) {
90901
- switchChain({ chainId: expectedChainId });
90902
- }
91054
+ if (switchChain) switchChain({ chainId: expectedChainId });
90903
91055
  };
90904
91056
  const handleTimerPassed = () => {
90905
- const newState = {
90906
- ...registrationState,
90907
- step: ProcessSteps.TimerCompleted
90908
- };
90909
- setRegistrationState(newState);
91057
+ setRegistrationState((prev) => ({ ...prev, step: ProcessSteps.TimerCompleted }));
90910
91058
  };
90911
91059
  const networkName = isTestnet ? "Sepolia" : "Mainnet";
90912
91060
  const handleCloseClick = () => {
@@ -90916,13 +91064,6 @@ const RegistrationProcess = ({
90916
91064
  onBack?.();
90917
91065
  }
90918
91066
  };
90919
- const handleConfirmClose = () => {
90920
- setShowConfirmClose(false);
90921
- onBack?.(true);
90922
- };
90923
- const handleCancelClose = () => {
90924
- setShowConfirmClose(false);
90925
- };
90926
91067
  return /* @__PURE__ */ jsxs("div", { className: "ens-registration-progress", children: [
90927
91068
  /* @__PURE__ */ jsx(
90928
91069
  "button",
@@ -90934,14 +91075,7 @@ const RegistrationProcess = ({
90934
91075
  children: /* @__PURE__ */ jsx(Icon, { name: "chevron-left", size: 16 })
90935
91076
  }
90936
91077
  ),
90937
- /* @__PURE__ */ jsx("div", { className: "d-flex justify-content-center", children: /* @__PURE__ */ jsx(
90938
- "img",
90939
- {
90940
- style: { width: "250px", margin: "auto" },
90941
- src: img$1,
90942
- alt: "Ninja Image"
90943
- }
90944
- ) }),
91078
+ /* @__PURE__ */ jsx("div", { className: "d-flex justify-content-center", children: /* @__PURE__ */ jsx("img", { style: { width: "250px", margin: "auto" }, src: img$1, alt: "Ninja Image" }) }),
90945
91079
  /* @__PURE__ */ jsxs("div", { className: "ns-text-center mt-2 mb-2", children: [
90946
91080
  /* @__PURE__ */ jsx(Text, { size: "lg", weight: "medium", children: "ENS Registration Process" }),
90947
91081
  /* @__PURE__ */ jsx(Text, { size: "xs", color: "grey", children: "Registration Consists of 3 Steps" })
@@ -90971,23 +91105,13 @@ const RegistrationProcess = ({
90971
91105
  }
90972
91106
  }
90973
91107
  ) }),
90974
- /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
90975
- TimerStep,
90976
- {
90977
- state: registrationState,
90978
- onTimerCompleted: () => {
90979
- handleTimerPassed();
90980
- }
90981
- }
90982
- ) }),
91108
+ /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(TimerStep, { state: registrationState, onTimerCompleted: handleTimerPassed }) }),
90983
91109
  /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(
90984
91110
  RegistrationStep,
90985
91111
  {
90986
91112
  state: registrationState,
90987
91113
  isTestnet,
90988
- onStateUpdated: (state) => {
90989
- setRegistrationState(state);
90990
- },
91114
+ onStateUpdated: setRegistrationState,
90991
91115
  onSuccess
90992
91116
  }
90993
91117
  ) })
@@ -90996,7 +91120,7 @@ const RegistrationProcess = ({
90996
91120
  Modal,
90997
91121
  {
90998
91122
  isOpen: showConfirmClose,
90999
- onClose: handleCancelClose,
91123
+ onClose: () => setShowConfirmClose(false),
91000
91124
  title: "Leave Registration?",
91001
91125
  size: "sm",
91002
91126
  footer: /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, width: "100%" }, children: [
@@ -91004,7 +91128,7 @@ const RegistrationProcess = ({
91004
91128
  Button,
91005
91129
  {
91006
91130
  variant: "outline",
91007
- onClick: handleCancelClose,
91131
+ onClick: () => setShowConfirmClose(false),
91008
91132
  style: { flex: 1 },
91009
91133
  children: "Cancel"
91010
91134
  }
@@ -91013,7 +91137,10 @@ const RegistrationProcess = ({
91013
91137
  Button,
91014
91138
  {
91015
91139
  variant: "destructive",
91016
- onClick: handleConfirmClose,
91140
+ onClick: () => {
91141
+ setShowConfirmClose(false);
91142
+ onBack?.(true);
91143
+ },
91017
91144
  style: { flex: 1 },
91018
91145
  children: "Leave"
91019
91146
  }
@@ -91025,38 +91152,27 @@ const RegistrationProcess = ({
91025
91152
  ] });
91026
91153
  };
91027
91154
 
91155
+ const REG_SECRET_PLACEHOLDER = "0x0000000000000000000000000000000000000000000000000000000000000001";
91028
91156
  const getLabel = (name) => {
91029
- if (!name) {
91030
- return "";
91031
- }
91032
- if (name.split(".").length !== 1) {
91033
- return name.split(".")[0];
91034
- }
91157
+ if (!name) return "";
91158
+ if (name.split(".").length !== 1) return name.split(".")[0];
91035
91159
  return name;
91036
91160
  };
91037
91161
  const EnsNameRegistrationForm = (props) => {
91162
+ const { address: connectedAddress } = useAccount();
91163
+ const { estimateRegistrationFees } = useRegisterENS({ isTestnet: props.isTestnet });
91038
91164
  const [label, setLabel] = useState(getLabel(props.name));
91039
- const [step, setStep] = useState(
91040
- 0 /* Summary */
91041
- );
91042
- const [years, setYears] = useState(1);
91165
+ const [step, setStep] = useState(0 /* Summary */);
91166
+ const [durationSeconds, setDurationSeconds] = useState(() => secondsFromYears(/* @__PURE__ */ new Date(), 1));
91043
91167
  const [regTxFees, setRegTxFees] = useState({
91044
91168
  estimatedGas: 0,
91045
91169
  isChecking: false,
91046
- price: {
91047
- wei: 0n,
91048
- eth: 1e-4
91049
- }
91050
- });
91051
- const [price, setPrice] = useState({
91052
- isChecking: false,
91053
- wei: 0n,
91054
- eth: 0
91055
- });
91056
- const [nameValidation, setNameValidation] = useState({
91057
- isChecking: false,
91058
- isTaken: false
91170
+ failed: false,
91171
+ isHeuristic: false,
91172
+ price: { wei: 0n, eth: 0 }
91059
91173
  });
91174
+ const [price, setPrice] = useState({ isChecking: false, wei: 0n, eth: 0 });
91175
+ const [nameValidation, setNameValidation] = useState({ isChecking: false, isTaken: false });
91060
91176
  const [showProfile, setShowProfile] = useState(false);
91061
91177
  const [ensRecordTemplate, setEnsRecordsTemplate] = useState({
91062
91178
  addresses: [],
@@ -91066,10 +91182,76 @@ const EnsNameRegistrationForm = (props) => {
91066
91182
  addresses: [],
91067
91183
  texts: []
91068
91184
  });
91069
- const hasRecordsDifference = useMemo(() => {
91070
- return getEnsRecordsDiff(ensRecords, ensRecordTemplate).isDifferent;
91071
- }, [ensRecords, ensRecordTemplate]);
91185
+ const hasRecordsDifference = useMemo(
91186
+ () => getEnsRecordsDiff(ensRecords, ensRecordTemplate).isDifferent,
91187
+ [ensRecords, ensRecordTemplate]
91188
+ );
91072
91189
  const [successData, setSuccessData] = useState();
91190
+ const feeRequestRef = useRef(0);
91191
+ const estimateFnRef = useRef(estimateRegistrationFees);
91192
+ const referrerRef = useRef(props.referrer);
91193
+ estimateFnRef.current = estimateRegistrationFees;
91194
+ referrerRef.current = props.referrer;
91195
+ const debouncedEstimate = useMemo(
91196
+ () => debounce(
91197
+ (requestId, params) => {
91198
+ estimateFnRef.current({
91199
+ label: params.label,
91200
+ owner: params.owner,
91201
+ durationInSeconds: params.durationInSeconds,
91202
+ secret: REG_SECRET_PLACEHOLDER,
91203
+ records: params.records,
91204
+ referrer: referrerRef.current
91205
+ }).then((result) => {
91206
+ if (feeRequestRef.current !== requestId) return;
91207
+ setRegTxFees({
91208
+ isChecking: false,
91209
+ failed: false,
91210
+ isHeuristic: result.isHeuristic,
91211
+ estimatedGas: Number(result.gasEstimate),
91212
+ price: { wei: result.wei, eth: result.eth }
91213
+ });
91214
+ }).catch(() => {
91215
+ if (feeRequestRef.current !== requestId) return;
91216
+ setRegTxFees({
91217
+ isChecking: false,
91218
+ failed: true,
91219
+ isHeuristic: false,
91220
+ estimatedGas: 0,
91221
+ price: { wei: 0n, eth: 0 }
91222
+ });
91223
+ });
91224
+ },
91225
+ 500
91226
+ ),
91227
+ []
91228
+ );
91229
+ useEffect(() => {
91230
+ if (!connectedAddress || !label || label.length < 3 || nameValidation.isChecking || nameValidation.isTaken || price.isChecking || price.eth <= 0) {
91231
+ feeRequestRef.current += 1;
91232
+ return;
91233
+ }
91234
+ const requestId = feeRequestRef.current + 1;
91235
+ feeRequestRef.current = requestId;
91236
+ setRegTxFees(
91237
+ (prev) => prev.isChecking && !prev.failed ? prev : { ...prev, isChecking: true, failed: false }
91238
+ );
91239
+ debouncedEstimate(requestId, {
91240
+ label,
91241
+ owner: connectedAddress,
91242
+ durationInSeconds: durationSeconds,
91243
+ records: ensRecords
91244
+ });
91245
+ }, [
91246
+ connectedAddress,
91247
+ label,
91248
+ durationSeconds,
91249
+ ensRecords,
91250
+ nameValidation.isChecking,
91251
+ nameValidation.isTaken,
91252
+ price.isChecking,
91253
+ price.eth
91254
+ ]);
91073
91255
  const handleSaveRecords = () => {
91074
91256
  setEnsRecords(deepCopy(ensRecordTemplate));
91075
91257
  setShowProfile(false);
@@ -91080,7 +91262,7 @@ const EnsNameRegistrationForm = (props) => {
91080
91262
  };
91081
91263
  const clearInputState = () => {
91082
91264
  setLabel("");
91083
- setYears(1);
91265
+ setDurationSeconds(secondsFromYears(/* @__PURE__ */ new Date(), 1));
91084
91266
  setEnsRecords({ addresses: [], texts: [] });
91085
91267
  setEnsRecordsTemplate({ addresses: [], texts: [] });
91086
91268
  setNameValidation({ isChecking: false, isTaken: false });
@@ -91111,18 +91293,18 @@ const EnsNameRegistrationForm = (props) => {
91111
91293
  RegistrationSummary,
91112
91294
  {
91113
91295
  label,
91114
- years,
91296
+ durationSeconds,
91115
91297
  price,
91116
91298
  nameValidation,
91117
91299
  isTestnet: props.isTestnet || false,
91118
- transactionFees: regTxFees,
91300
+ transactionFees: connectedAddress ? regTxFees : void 0,
91119
91301
  title: props.title,
91120
91302
  subtitle: props.subtitle,
91121
91303
  bannerImage: props.bannerImage,
91122
91304
  hideBanner: props.hideBanner,
91123
91305
  bannerWidth: props.bannerWidth,
91124
91306
  onLabelChange: setLabel,
91125
- onYearsChange: setYears,
91307
+ onDurationChange: setDurationSeconds,
91126
91308
  onPriceChange: setPrice,
91127
91309
  onNameValidationChange: setNameValidation,
91128
91310
  onSetProfile: () => setShowProfile(true),
@@ -91136,13 +91318,11 @@ const EnsNameRegistrationForm = (props) => {
91136
91318
  {
91137
91319
  isTestnet: props.isTestnet || false,
91138
91320
  label,
91139
- expiryInYears: years,
91321
+ durationInSeconds: durationSeconds,
91140
91322
  records: ensRecords,
91141
91323
  referrer: props.referrer,
91142
91324
  onBack: (clearState) => {
91143
- if (clearState) {
91144
- clearInputState();
91145
- }
91325
+ if (clearState) clearInputState();
91146
91326
  setStep(0 /* Summary */);
91147
91327
  },
91148
91328
  onStart: props.onRegistrationStart,
@@ -91157,7 +91337,7 @@ const EnsNameRegistrationForm = (props) => {
91157
91337
  SuccessScreen$1,
91158
91338
  {
91159
91339
  ensName: label,
91160
- expiryInYears: successData.expiryInYears,
91340
+ durationLabel: successData.durationLabel,
91161
91341
  registrationCost: successData.registrationCost,
91162
91342
  transactionFees: successData.transactionFees,
91163
91343
  total: successData.total,
@@ -92620,7 +92800,7 @@ const SubnameMintFormContent = ({
92620
92800
  const hasRecordsDifference = useMemo(() => {
92621
92801
  return getEnsRecordsDiff(ensRecords, ensRecordTemplate).isDifferent;
92622
92802
  }, [ensRecords, ensRecordTemplate]);
92623
- const [years, setYears] = useState(1);
92803
+ const [durationSeconds, setDurationSeconds] = useState(() => secondsFromYears(/* @__PURE__ */ new Date(), 1));
92624
92804
  const [availability, setAvailability] = useState({
92625
92805
  isChecking: false,
92626
92806
  isAvailable: true
@@ -92714,11 +92894,8 @@ const SubnameMintFormContent = ({
92714
92894
  isFree: isFree2
92715
92895
  };
92716
92896
  }, [mintDetails, transactionFees]);
92717
- const handleYearsChange = (newYears) => {
92718
- if (newYears < 1) {
92719
- return;
92720
- }
92721
- setYears(newYears);
92897
+ const handleDurationChange = (seconds) => {
92898
+ setDurationSeconds(seconds);
92722
92899
  };
92723
92900
  const totalPriceLoading = transactionFees.isChecking || mintDetails.isChecking;
92724
92901
  const transactionFeesLoading = transactionFees.isChecking;
@@ -93021,8 +93198,8 @@ const SubnameMintFormContent = ({
93021
93198
  isChecking: totalPriceLoading
93022
93199
  },
93023
93200
  expiryPicker: isExpirable ? {
93024
- years,
93025
- onYearsChange: handleYearsChange
93201
+ durationSeconds,
93202
+ onDurationChange: handleDurationChange
93026
93203
  } : void 0,
93027
93204
  ethUsdRate
93028
93205
  }
@@ -93629,5 +93806,5 @@ const useTheme = () => {
93629
93806
  return ctx;
93630
93807
  };
93631
93808
 
93632
- export { Accordion, Alert, Button, Card, ChainIcon, ConnectAndSetChain, ContenthashIcon, ContenthashProtocol, ContractErrorLabel, Dropdown, ENS_RESOLVER_ABI, EnsNameRegistrationForm, EnsRecordsForm, Icon, Input, ListingNetwork, ListingType, MULTICALL, Modal, OffchainSubnameForm, PricingDisplay, ProfileHeader, ProgressBar, SET_ADDRESS_FUNC, SET_CONTENTHASH_FUNC, SET_TEXT_FUNC, SelectRecordsForm, ShurikenSpinner, SubnameMintForm, Text, TextRecordCategory, Textarea, ThemeProvider, Tooltip, TransactionPendingScreen, TxProgress, capitalize, convertEVMChainIdToCoinType, convertToMulticallResolverData, convertToResolverData, createEnsReferer, debounce, deepCopy, diffToEnsRecords, ensureFloatInput, equalsIgnoreCase, formatFloat, getAvatarUploadErrorMessage, getBlockExplorer, getBlockExplorerAddressUrl, getBlockExplorerName, getBlockExplorerTransactionUrl, getChainIdForListingNetwork, getEnsAppUrl, getEnsRecordsDiff, getImageUploadErrorMessage, getSupportedAddressByChainId, getSupportedAddressByCoin, getSupportedAddressByName, getSupportedAddressMap, getSupportedChashByProtocol, getSupportedText, isCommitmentToNewErr, isContenthashValid, isUserDeniedError, supportedAddresses, supportedContenthashRecords, supportedTexts, useAvatarClient, useENSResolver, useEthDollarValue, useMintManager, useMintSubname, useOffchainManager, useRegisterENS, useTheme, useWaitTransaction, validateEnsRecords, wait };
93809
+ export { Accordion, Alert, Button, Card, ChainIcon, ConnectAndSetChain, ContenthashIcon, ContenthashProtocol, ContractErrorLabel, Dropdown, DurationPicker, ENS_RESOLVER_ABI, EnsNameRegistrationForm, EnsRecordsForm, Icon, Input, ListingNetwork, ListingType, MIN_REGISTRATION_SECONDS, MULTICALL, Modal, ONE_DAY, ONE_YEAR, OffchainSubnameForm, PricingDisplay, ProfileHeader, ProgressBar, SET_ADDRESS_FUNC, SET_CONTENTHASH_FUNC, SET_TEXT_FUNC, SelectRecordsForm, ShurikenSpinner, SubnameMintForm, Text, TextRecordCategory, Textarea, ThemeProvider, Tooltip, TransactionPendingScreen, TxProgress, capitalize, convertEVMChainIdToCoinType, convertToMulticallResolverData, convertToResolverData, createEnsReferer, debounce, deepCopy, diffToEnsRecords, ensureFloatInput, equalsIgnoreCase, formatDurationSummary, formatFloat, getAvatarUploadErrorMessage, getBlockExplorer, getBlockExplorerAddressUrl, getBlockExplorerName, getBlockExplorerTransactionUrl, getChainIdForListingNetwork, getEnsAppUrl, getEnsRecordsDiff, getImageUploadErrorMessage, getSupportedAddressByChainId, getSupportedAddressByCoin, getSupportedAddressByName, getSupportedAddressMap, getSupportedChashByProtocol, getSupportedText, isCommitmentToNewErr, isContenthashValid, isUserDeniedError, roundDurationWithDay, secondsFromYears, secondsToDateInput, supportedAddresses, supportedContenthashRecords, supportedTexts, useAvatarClient, useENSResolver, useEthDollarValue, useMintManager, useMintSubname, useOffchainManager, useRegisterENS, useTheme, useWaitTransaction, validateEnsRecords, wait, yearsFromSeconds };
93633
93810
  //# sourceMappingURL=index.js.map