diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx
index 1be4644c..da93d587 100644
--- a/apps/example/src/App.tsx
+++ b/apps/example/src/App.tsx
@@ -11,12 +11,31 @@ import {
useQuery,
useQueryWithRefresh,
useWallets,
+ useChainSpecData,
} from "@reactive-dot/react";
+import { DenominatedNumber } from "@reactive-dot/utils";
import { formatDistance } from "date-fns";
import { Binary } from "polkadot-api";
import { Suspense, useState, useTransition } from "react";
import { ErrorBoundary, type FallbackProps } from "react-error-boundary";
+const useNativeTokenNumberWithPlanck = (planck: bigint) => {
+ const chainSpecData = useChainSpecData();
+
+ return new DenominatedNumber(
+ planck,
+ chainSpecData.properties.tokenDecimals,
+ chainSpecData.properties.tokenSymbol,
+ );
+};
+
+const PendingRewards = (props: { address: string; rewards: bigint }) => (
+
+ {props.address}:{" "}
+ {useNativeTokenNumberWithPlanck(props.rewards).toLocaleString()}
+
+);
+
const PendingPoolRewards = () => {
const accounts = useAccounts();
@@ -47,9 +66,11 @@ const PendingPoolRewards = () => {
{pendingRewards.map((rewards, index) => (
- -
- {accounts.at(index)?.address}: {rewards.toLocaleString()} planck
-
+
))}
@@ -111,7 +132,7 @@ const Query = () => {
Total issuance
- {totalIssuance.toLocaleString()} planck
+ {useNativeTokenNumberWithPlanck(totalIssuance).toLocaleString()}
Bonding duration
@@ -119,11 +140,15 @@ const Query = () => {
Total value staked
- {totalStaked?.toLocaleString()} planck
+
+ {useNativeTokenNumberWithPlanck(totalStaked ?? 0n).toLocaleString()}
+
Total value locked in nomination Pools
- {totalValueLocked.toLocaleString()} planck
+
+ {useNativeTokenNumberWithPlanck(totalValueLocked).toLocaleString()}
+
First 4 pools
diff --git a/nx.json b/nx.json
index 4c87c33b..64a5c028 100644
--- a/nx.json
+++ b/nx.json
@@ -14,8 +14,9 @@
"cache": true
},
"test": {
+ "dependsOn": ["^build"],
"cache": true
}
},
- "parallel": 5
+ "parallel": 6
}
diff --git a/packages/core/package.json b/packages/core/package.json
index 5d25080e..ee89b0bd 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -47,5 +47,8 @@
"@walletconnect/universal-provider": {
"optional": true
}
+ },
+ "dependencies": {
+ "@reactive-dot/utils": "workspace:^"
}
}
diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json
index 415bf217..f80c6f79 100644
--- a/packages/eslint-config/package.json
+++ b/packages/eslint-config/package.json
@@ -4,9 +4,6 @@
"private": true,
"type": "module",
"main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
"devDependencies": {
"@eslint/compat": "^1.0.3",
"@eslint/js": "^9.4.0",
diff --git a/packages/react/src/hooks/useChainSpecData.ts b/packages/react/src/hooks/useChainSpecData.ts
new file mode 100644
index 00000000..7ddffe6f
--- /dev/null
+++ b/packages/react/src/hooks/useChainSpecData.ts
@@ -0,0 +1,23 @@
+import { ChainIdContext } from "../context.js";
+import { chainSpecDataAtomFamily } from "../stores/client.js";
+import type { ChainHookOptions } from "./types.js";
+import { ReDotError } from "@reactive-dot/core";
+import { useAtomValue } from "jotai";
+import { useContext } from "react";
+
+/**
+ * Hook for fetching the [JSON-RPC spec](https://paritytech.github.io/json-rpc-interface-spec/api/chainSpec.html).
+ *
+ * @param options - Additional options
+ * @returns The [JSON-RPC spec](https://paritytech.github.io/json-rpc-interface-spec/api/chainSpec.html)
+ */
+export const useChainSpecData = (options?: ChainHookOptions) => {
+ const contextChainId = useContext(ChainIdContext);
+ const chainId = options?.chainId ?? contextChainId;
+
+ if (chainId === undefined) {
+ throw new ReDotError("No chain Id provided");
+ }
+
+ return useAtomValue(chainSpecDataAtomFamily(chainId));
+};
diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts
index 34fa7d54..f69799a2 100644
--- a/packages/react/src/index.ts
+++ b/packages/react/src/index.ts
@@ -9,6 +9,7 @@ export {
export type { ChainHookOptions } from "./hooks/types.js";
export { useAccounts } from "./hooks/useAccounts.js";
export { useBlock } from "./hooks/useBlock.js";
+export { useChainSpecData } from "./hooks/useChainSpecData.js";
export { useClient } from "./hooks/useClient.js";
export { useMutation } from "./hooks/useMutation.js";
export { useQuery, useQueryWithRefresh } from "./hooks/useQuery.js";
diff --git a/packages/utils/.gitignore b/packages/utils/.gitignore
new file mode 100644
index 00000000..378eac25
--- /dev/null
+++ b/packages/utils/.gitignore
@@ -0,0 +1 @@
+build
diff --git a/packages/utils/eslint.config.js b/packages/utils/eslint.config.js
new file mode 100644
index 00000000..52e9273c
--- /dev/null
+++ b/packages/utils/eslint.config.js
@@ -0,0 +1,4 @@
+import recommended from "@reactive-dot/eslint-config";
+import tseslint from "typescript-eslint";
+
+export default tseslint.config(...recommended);
diff --git a/packages/utils/package.json b/packages/utils/package.json
new file mode 100644
index 00000000..feb42a3e
--- /dev/null
+++ b/packages/utils/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "@reactive-dot/utils",
+ "version": "0.0.0",
+ "type": "module",
+ "files": [
+ "src",
+ "build"
+ ],
+ "exports": {
+ ".": {
+ "default": "./build/index.js",
+ "types": "./src/index.ts"
+ }
+ },
+ "scripts": {
+ "dev": "tsc --build --watch",
+ "build": "rm -rf build && tsc --build",
+ "lint": "eslint src",
+ "test": "vitest run"
+ },
+ "devDependencies": {
+ "@reactive-dot/eslint-config": "workspace:^",
+ "@tsconfig/recommended": "^1.0.6",
+ "@tsconfig/strictest": "^2.0.5",
+ "eslint": "^9.4.0",
+ "typescript": "^5.4.5",
+ "vitest": "^1.6.0"
+ }
+}
diff --git a/packages/utils/src/DenominatedNumber.test.ts b/packages/utils/src/DenominatedNumber.test.ts
new file mode 100644
index 00000000..ae3e8d03
--- /dev/null
+++ b/packages/utils/src/DenominatedNumber.test.ts
@@ -0,0 +1,249 @@
+import DenominatedNumber from "./DenominatedNumber.js";
+import { describe, expect, it } from "vitest";
+
+describe("DenominatedNumber", () => {
+ describe("fromPlanck", () => {
+ it("leads to correct atomics value", () => {
+ expect(new DenominatedNumber("1", 0).planck).toEqual(1n);
+ expect(new DenominatedNumber("1", 1).planck).toEqual(1n);
+ expect(new DenominatedNumber("1", 2).planck).toEqual(1n);
+
+ expect(new DenominatedNumber("1", 5).planck).toEqual(1n);
+ expect(new DenominatedNumber("2", 5).planck).toEqual(2n);
+ expect(new DenominatedNumber("3", 5).planck).toEqual(3n);
+ expect(new DenominatedNumber("10", 5).planck).toEqual(10n);
+ expect(new DenominatedNumber("20", 5).planck).toEqual(20n);
+ expect(new DenominatedNumber("30", 5).planck).toEqual(30n);
+ expect(
+ new DenominatedNumber("100000000000000000000000", 5).planck,
+ ).toEqual(100000000000000000000000n);
+ expect(
+ new DenominatedNumber("200000000000000000000000", 5).planck,
+ ).toEqual(200000000000000000000000n);
+ expect(
+ new DenominatedNumber("300000000000000000000000", 5).planck,
+ ).toEqual(300000000000000000000000n);
+
+ expect(new DenominatedNumber("44", 5).planck).toEqual(44n);
+ expect(new DenominatedNumber("044", 5).planck).toEqual(44n);
+ expect(new DenominatedNumber("0044", 5).planck).toEqual(44n);
+ expect(new DenominatedNumber("00044", 5).planck).toEqual(44n);
+ });
+
+ it("reads DenominatedNumbers correctly", () => {
+ expect(new DenominatedNumber("44", 0).toString()).toEqual("44");
+ expect(new DenominatedNumber("44", 1).toString()).toEqual("4.4");
+ expect(new DenominatedNumber("44", 2).toString()).toEqual("0.44");
+ expect(new DenominatedNumber("44", 3).toString()).toEqual("0.044");
+ expect(new DenominatedNumber("44", 4).toString()).toEqual("0.0044");
+ });
+
+ it("reads negative integer correctly", () => {
+ expect(new DenominatedNumber("-44", 0).toString()).toEqual("-44");
+ expect(new DenominatedNumber("-44", 1).toString()).toEqual("-4.4");
+ });
+ });
+
+ describe("fromNumber", () => {
+ it("throws helpful error message for invalid characters", () => {
+ expect(() => DenominatedNumber.fromNumber(" 13", 5)).toThrowError(
+ /invalid character at position 1/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("1,3", 5)).toThrowError(
+ /invalid character at position 2/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("13-", 5)).toThrowError(
+ /invalid character at position 3/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("13/", 5)).toThrowError(
+ /invalid character at position 3/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("13\\", 5)).toThrowError(
+ /invalid character at position 3/i,
+ );
+ });
+
+ it("throws for more than one separator", () => {
+ expect(() => DenominatedNumber.fromNumber("1.3.5", 5)).toThrowError(
+ /more than one separator found/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("1..3", 5)).toThrowError(
+ /more than one separator found/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("..", 5)).toThrowError(
+ /more than one separator found/i,
+ );
+ });
+
+ it("throws for separator only", () => {
+ expect(() => DenominatedNumber.fromNumber(".", 5)).toThrowError(
+ /fractional part missing/i,
+ );
+ });
+
+ it.skip("throws for more decimals than supported", () => {
+ expect(() => DenominatedNumber.fromNumber("44.123456", 5)).toThrowError(
+ /got more DenominatedNumbers than supported/i,
+ );
+ expect(() => DenominatedNumber.fromNumber("44.1", 0)).toThrowError(
+ /got more DenominatedNumbers than supported/i,
+ );
+ });
+
+ it("throws for decimals that are not non-negative integers", () => {
+ // no integer
+ expect(() => DenominatedNumber.fromNumber("1", Number.NaN)).toThrowError(
+ /Decimals is not an integer/i,
+ );
+ expect(() =>
+ DenominatedNumber.fromNumber("1", Number.POSITIVE_INFINITY),
+ ).toThrowError(/Decimals is not an integer/i);
+ expect(() =>
+ DenominatedNumber.fromNumber("1", Number.NEGATIVE_INFINITY),
+ ).toThrowError(/Decimals is not an integer/i);
+ expect(() =>
+ DenominatedNumber.fromNumber("1", 1.78945544484),
+ ).toThrowError(/Decimals is not an integer/i);
+
+ // negative
+ expect(() => DenominatedNumber.fromNumber("1", -1)).toThrowError(
+ /Decimals must not be negative/i,
+ );
+ expect(() =>
+ DenominatedNumber.fromNumber("1", Number.MIN_SAFE_INTEGER),
+ ).toThrowError(/Decimals must not be negative/i);
+
+ // exceeds supported range
+ expect(() => DenominatedNumber.fromNumber("1", 101)).toThrowError(
+ /Decimals must not exceed 100/i,
+ );
+ });
+
+ it("returns correct value", () => {
+ expect(DenominatedNumber.fromNumber("44", 0).planck).toEqual(44n);
+ expect(DenominatedNumber.fromNumber("44", 1).planck).toEqual(440n);
+ expect(DenominatedNumber.fromNumber("44", 2).planck).toEqual(4400n);
+ expect(DenominatedNumber.fromNumber("44", 3).planck).toEqual(44000n);
+
+ expect(DenominatedNumber.fromNumber("44.2", 1).planck).toEqual(442n);
+ expect(DenominatedNumber.fromNumber("44.2", 2).planck).toEqual(4420n);
+ expect(DenominatedNumber.fromNumber("44.2", 3).planck).toEqual(44200n);
+
+ expect(DenominatedNumber.fromNumber("44.1", 6).planck).toEqual(44100000n);
+ expect(DenominatedNumber.fromNumber("44.12", 6).planck).toEqual(
+ 44120000n,
+ );
+ expect(DenominatedNumber.fromNumber("44.123", 6).planck).toEqual(
+ 44123000n,
+ );
+ expect(DenominatedNumber.fromNumber("44.1234", 6).planck).toEqual(
+ 44123400n,
+ );
+ expect(DenominatedNumber.fromNumber("44.12345", 6).planck).toEqual(
+ 44123450n,
+ );
+ expect(DenominatedNumber.fromNumber("44.123456", 6).planck).toEqual(
+ 44123456n,
+ );
+ });
+
+ it("cuts leading zeros", () => {
+ expect(DenominatedNumber.fromNumber("4", 2).planck).toEqual(400n);
+ expect(DenominatedNumber.fromNumber("04", 2).planck).toEqual(400n);
+ expect(DenominatedNumber.fromNumber("004", 2).planck).toEqual(400n);
+ });
+
+ it("cuts tailing zeros", () => {
+ expect(DenominatedNumber.fromNumber("4.12", 5).planck).toEqual(412000n);
+ expect(DenominatedNumber.fromNumber("4.120", 5).planck).toEqual(412000n);
+ expect(DenominatedNumber.fromNumber("4.1200", 5).planck).toEqual(412000n);
+ expect(DenominatedNumber.fromNumber("4.12000", 5).planck).toEqual(
+ 412000n,
+ );
+ expect(DenominatedNumber.fromNumber("4.120000", 5).planck).toEqual(
+ 412000n,
+ );
+ expect(DenominatedNumber.fromNumber("4.1200000", 5).planck).toEqual(
+ 412000n,
+ );
+ });
+
+ it("interprets the empty string as zero", () => {
+ expect(DenominatedNumber.fromNumber("", 0).planck).toEqual(0n);
+ expect(DenominatedNumber.fromNumber("", 1).planck).toEqual(0n);
+ expect(DenominatedNumber.fromNumber("", 2).planck).toEqual(0n);
+ expect(DenominatedNumber.fromNumber("", 3).planck).toEqual(0n);
+ });
+
+ it("accepts american notation with skipped leading zero", () => {
+ expect(DenominatedNumber.fromNumber(".1", 3).planck).toEqual(100n);
+ expect(DenominatedNumber.fromNumber(".12", 3).planck).toEqual(120n);
+ expect(DenominatedNumber.fromNumber(".123", 3).planck).toEqual(123n);
+ });
+ });
+
+ describe("toString", () => {
+ it("displays no decimals point for full numbers", () => {
+ expect(DenominatedNumber.fromNumber("44", 0).toString()).toEqual("44");
+ expect(DenominatedNumber.fromNumber("44", 1).toString()).toEqual("44");
+ expect(DenominatedNumber.fromNumber("44", 2).toString()).toEqual("44");
+
+ expect(DenominatedNumber.fromNumber("44", 2).toString()).toEqual("44");
+ expect(DenominatedNumber.fromNumber("44.0", 2).toString()).toEqual("44");
+ expect(DenominatedNumber.fromNumber("44.00", 2).toString()).toEqual("44");
+ expect(DenominatedNumber.fromNumber("44.000", 2).toString()).toEqual(
+ "44",
+ );
+ });
+
+ it("only shows significant digits", () => {
+ expect(DenominatedNumber.fromNumber("44.1", 2).toString()).toEqual(
+ "44.1",
+ );
+ expect(DenominatedNumber.fromNumber("44.10", 2).toString()).toEqual(
+ "44.1",
+ );
+ expect(DenominatedNumber.fromNumber("44.100", 2).toString()).toEqual(
+ "44.1",
+ );
+ });
+
+ it("fills up leading zeros", () => {
+ expect(new DenominatedNumber("3", 0).toString()).toEqual("3");
+ expect(new DenominatedNumber("3", 1).toString()).toEqual("0.3");
+ expect(new DenominatedNumber("3", 2).toString()).toEqual("0.03");
+ expect(new DenominatedNumber("3", 3).toString()).toEqual("0.003");
+ });
+
+ it("handles zero value", () => {
+ expect(new DenominatedNumber(0, 18).toString()).toEqual("0");
+ });
+ });
+
+ describe("toNumber", () => {
+ it("works", () => {
+ expect(DenominatedNumber.fromNumber("0", 5).valueOf()).toEqual(0);
+ expect(DenominatedNumber.fromNumber("1", 5).valueOf()).toEqual(1);
+ expect(DenominatedNumber.fromNumber("1.5", 5).valueOf()).toEqual(1.5);
+ expect(DenominatedNumber.fromNumber("0.1", 5).valueOf()).toEqual(0.1);
+
+ expect(
+ DenominatedNumber.fromNumber("1234500000000000", 5).valueOf(),
+ ).toEqual(1.2345e15);
+ expect(
+ DenominatedNumber.fromNumber("1234500000000000.002", 5).valueOf(),
+ ).toEqual(1.2345e15);
+ });
+ });
+
+ describe("toLocaleString", () => {
+ it("Add denomination to the string value", () => {
+ const string = new DenominatedNumber(30, 0, "DOT").toLocaleString(
+ "en-NZ",
+ );
+
+ expect(string).toContain("DOT");
+ expect(string).toContain("30.00");
+ });
+ });
+});
diff --git a/packages/utils/src/DenominatedNumber.ts b/packages/utils/src/DenominatedNumber.ts
new file mode 100644
index 00000000..ebd74411
--- /dev/null
+++ b/packages/utils/src/DenominatedNumber.ts
@@ -0,0 +1,141 @@
+export default class DenominatedNumber extends Number {
+ // Large values lead to massive memory usage. Limit to something sensible.
+ static #maxDecimal = 100;
+
+ readonly planck: bigint;
+
+ constructor(
+ planck: bigint | boolean | number | string,
+ readonly decimals: number,
+ readonly denomination?: string,
+ ) {
+ super();
+ this.planck = BigInt(planck);
+ }
+
+ static fromNumber(
+ number: number | string,
+ decimals: number,
+ denomination?: string,
+ ) {
+ DenominatedNumber.#verifyDecimals(decimals);
+
+ const numberString = number.toString();
+
+ const badCharacter = numberString.match(/[^0-9.]/);
+ if (badCharacter) {
+ throw new Error(
+ `Invalid character at position ${(badCharacter.index ?? 0) + 1}`,
+ );
+ }
+
+ let whole: string;
+ let fractional: string;
+
+ if (numberString.search(/\./) === -1) {
+ // integer format, no separator
+ whole = numberString;
+ fractional = "";
+ } else {
+ const parts = numberString.split(".");
+ switch (parts.length) {
+ case 0:
+ case 1:
+ throw new Error(
+ "Fewer than two elements in split result. This must not happen here.",
+ );
+ case 2:
+ if (!parts[1]) throw new Error("Fractional part missing");
+
+ whole = parts[0]!;
+ fractional = parts[1].replace(/0+$/, "");
+ break;
+ default:
+ throw new Error("More than one separator found");
+ }
+ }
+
+ if (fractional.length > decimals) {
+ fractional = fractional.slice(0, decimals);
+ }
+
+ const quantity = `${whole}${fractional.padEnd(decimals, "0")}`;
+
+ return new DenominatedNumber(BigInt(quantity), decimals, denomination);
+ }
+
+ override valueOf() {
+ return Number(this.toString());
+ }
+
+ override toString() {
+ const paddedPlanck = this.planck.toString().padStart(this.decimals, "0");
+ const whole = paddedPlanck
+ .slice(0, paddedPlanck.length - this.decimals)
+ .padStart(1, "0");
+ const fractional = paddedPlanck
+ .slice(paddedPlanck.length - this.decimals)
+ .replace(/0+$/, "");
+
+ if (fractional.length === 0) {
+ return whole;
+ } else {
+ return `${whole || "0"}.${fractional}`;
+ }
+ }
+
+ override toLocaleString(
+ locales?: string | string[] | undefined,
+ options?: Intl.NumberFormatOptions | undefined,
+ ): string;
+ override toLocaleString(
+ locales?: Intl.LocalesArgument,
+ options?: Intl.NumberFormatOptions | undefined,
+ ): string;
+ override toLocaleString(
+ locales?: Intl.LocalesArgument | string | string[] | undefined,
+ options?: Intl.NumberFormatOptions | undefined,
+ ) {
+ if (this.denomination === undefined) {
+ return this.valueOf().toLocaleString(locales, options);
+ }
+
+ const newOptions: Intl.NumberFormatOptions = {};
+
+ if (options?.style === undefined) {
+ newOptions.style = "currency";
+ newOptions.currency = "XTS";
+ }
+
+ return this.valueOf()
+ .toLocaleString(locales, newOptions)
+ .replace("XTS", this.denomination);
+ }
+
+ mapFromPlanck(mapper: (planck: bigint) => bigint) {
+ return new DenominatedNumber(
+ mapper(this.planck),
+ this.decimals,
+ this.denomination,
+ );
+ }
+
+ mapFromNumber(mapper: (number: number) => number) {
+ return DenominatedNumber.fromNumber(
+ mapper(this.valueOf()),
+ this.decimals,
+ this.denomination,
+ );
+ }
+
+ static #verifyDecimals(fractionalDigits: number): void {
+ if (!Number.isInteger(fractionalDigits))
+ throw new Error("Decimals is not an integer");
+ if (fractionalDigits < 0) throw new Error("Decimals must not be negative");
+ if (fractionalDigits > DenominatedNumber.#maxDecimal) {
+ throw new Error(
+ `Decimals must not exceed ${DenominatedNumber.#maxDecimal}`,
+ );
+ }
+ }
+}
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
new file mode 100644
index 00000000..9af811bc
--- /dev/null
+++ b/packages/utils/src/index.ts
@@ -0,0 +1 @@
+export { default as DenominatedNumber } from "./DenominatedNumber.js";
diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json
new file mode 100644
index 00000000..30a1d007
--- /dev/null
+++ b/packages/utils/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "extends": [
+ "@tsconfig/recommended/tsconfig.json",
+ "@tsconfig/strictest/tsconfig.json"
+ ],
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "NodeNext",
+ "moduleResolution": "NodeNext",
+ "jsx": "react-jsx",
+ "outDir": "build"
+ },
+ "include": ["src"],
+ "exclude": ["**/*.test.*"]
+}
diff --git a/yarn.lock b/yarn.lock
index cb4c3e82..c80fc679 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2827,7 +2827,7 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14":
+"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15":
version: 1.4.15
resolution: "@jridgewell/sourcemap-codec@npm:1.4.15"
checksum: 10c0/0c6b5ae663087558039052a626d2d7ed5208da36cfd707dcc5cea4a07cfc918248403dcb5989a8f7afaf245ce0573b7cc6fd94c4a30453bd10e44d9363940ba5
@@ -3593,6 +3593,7 @@ __metadata:
resolution: "@reactive-dot/core@workspace:packages/core"
dependencies:
"@reactive-dot/eslint-config": "workspace:^"
+ "@reactive-dot/utils": "workspace:^"
"@tsconfig/recommended": "npm:^1.0.6"
"@tsconfig/strictest": "npm:^2.0.5"
"@walletconnect/modal": "npm:^2.6.2"
@@ -3691,6 +3692,19 @@ __metadata:
languageName: unknown
linkType: soft
+"@reactive-dot/utils@workspace:^, @reactive-dot/utils@workspace:packages/utils":
+ version: 0.0.0-use.local
+ resolution: "@reactive-dot/utils@workspace:packages/utils"
+ dependencies:
+ "@reactive-dot/eslint-config": "workspace:^"
+ "@tsconfig/recommended": "npm:^1.0.6"
+ "@tsconfig/strictest": "npm:^2.0.5"
+ eslint: "npm:^9.4.0"
+ typescript: "npm:^5.4.5"
+ vitest: "npm:^1.6.0"
+ languageName: unknown
+ linkType: soft
+
"@rollup/rollup-android-arm-eabi@npm:4.18.0":
version: 4.18.0
resolution: "@rollup/rollup-android-arm-eabi@npm:4.18.0"
@@ -4888,6 +4902,60 @@ __metadata:
languageName: node
linkType: hard
+"@vitest/expect@npm:1.6.0":
+ version: 1.6.0
+ resolution: "@vitest/expect@npm:1.6.0"
+ dependencies:
+ "@vitest/spy": "npm:1.6.0"
+ "@vitest/utils": "npm:1.6.0"
+ chai: "npm:^4.3.10"
+ checksum: 10c0/a4351f912a70543e04960f5694f1f1ac95f71a856a46e87bba27d3eb72a08c5d11d35021cbdc6077452a152e7d93723fc804bba76c2cc53c8896b7789caadae3
+ languageName: node
+ linkType: hard
+
+"@vitest/runner@npm:1.6.0":
+ version: 1.6.0
+ resolution: "@vitest/runner@npm:1.6.0"
+ dependencies:
+ "@vitest/utils": "npm:1.6.0"
+ p-limit: "npm:^5.0.0"
+ pathe: "npm:^1.1.1"
+ checksum: 10c0/27d67fa51f40effe0e41ee5f26563c12c0ef9a96161f806036f02ea5eb9980c5cdf305a70673942e7a1e3d472d4d7feb40093ae93024ef1ccc40637fc65b1d2f
+ languageName: node
+ linkType: hard
+
+"@vitest/snapshot@npm:1.6.0":
+ version: 1.6.0
+ resolution: "@vitest/snapshot@npm:1.6.0"
+ dependencies:
+ magic-string: "npm:^0.30.5"
+ pathe: "npm:^1.1.1"
+ pretty-format: "npm:^29.7.0"
+ checksum: 10c0/be027fd268d524589ff50c5fad7b4faa1ac5742b59ac6c1dc6f5a3930aad553560e6d8775e90ac4dfae4be746fc732a6f134ba95606a1519707ce70db3a772a5
+ languageName: node
+ linkType: hard
+
+"@vitest/spy@npm:1.6.0":
+ version: 1.6.0
+ resolution: "@vitest/spy@npm:1.6.0"
+ dependencies:
+ tinyspy: "npm:^2.2.0"
+ checksum: 10c0/df66ea6632b44fb76ef6a65c1abbace13d883703aff37cd6d062add6dcd1b883f19ce733af8e0f7feb185b61600c6eb4042a518e4fb66323d0690ec357f9401c
+ languageName: node
+ linkType: hard
+
+"@vitest/utils@npm:1.6.0":
+ version: 1.6.0
+ resolution: "@vitest/utils@npm:1.6.0"
+ dependencies:
+ diff-sequences: "npm:^29.6.3"
+ estree-walker: "npm:^3.0.3"
+ loupe: "npm:^2.3.7"
+ pretty-format: "npm:^29.7.0"
+ checksum: 10c0/8b0d19835866455eb0b02b31c5ca3d8ad45f41a24e4c7e1f064b480f6b2804dc895a70af332f14c11ed89581011b92b179718523f55f5b14787285a0321b1301
+ languageName: node
+ linkType: hard
+
"@vscode/codicons@npm:^0.0.35":
version: 0.0.35
resolution: "@vscode/codicons@npm:0.0.35"
@@ -5421,7 +5489,7 @@ __metadata:
languageName: node
linkType: hard
-"acorn-walk@npm:^8.0.0":
+"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.3.2":
version: 8.3.2
resolution: "acorn-walk@npm:8.3.2"
checksum: 10c0/7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52
@@ -5802,6 +5870,13 @@ __metadata:
languageName: node
linkType: hard
+"assertion-error@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "assertion-error@npm:1.1.0"
+ checksum: 10c0/25456b2aa333250f01143968e02e4884a34588a8538fbbf65c91a637f1dbfb8069249133cd2f4e530f10f624d206a664e7df30207830b659e9f5298b00a4099b
+ languageName: node
+ linkType: hard
+
"astring@npm:^1.8.0":
version: 1.8.6
resolution: "astring@npm:1.8.6"
@@ -6134,7 +6209,7 @@ __metadata:
languageName: node
linkType: hard
-"cac@npm:^6.7.12":
+"cac@npm:^6.7.12, cac@npm:^6.7.14":
version: 6.7.14
resolution: "cac@npm:6.7.14"
checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10
@@ -6260,6 +6335,21 @@ __metadata:
languageName: node
linkType: hard
+"chai@npm:^4.3.10":
+ version: 4.4.1
+ resolution: "chai@npm:4.4.1"
+ dependencies:
+ assertion-error: "npm:^1.1.0"
+ check-error: "npm:^1.0.3"
+ deep-eql: "npm:^4.1.3"
+ get-func-name: "npm:^2.0.2"
+ loupe: "npm:^2.3.6"
+ pathval: "npm:^1.1.1"
+ type-detect: "npm:^4.0.8"
+ checksum: 10c0/91590a8fe18bd6235dece04ccb2d5b4ecec49984b50924499bdcd7a95c02cb1fd2a689407c19bb854497bde534ef57525cfad6c7fdd2507100fd802fbc2aefbd
+ languageName: node
+ linkType: hard
+
"chalk@npm:^2.4.2":
version: 2.4.2
resolution: "chalk@npm:2.4.2"
@@ -6323,6 +6413,15 @@ __metadata:
languageName: node
linkType: hard
+"check-error@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "check-error@npm:1.0.3"
+ dependencies:
+ get-func-name: "npm:^2.0.2"
+ checksum: 10c0/94aa37a7315c0e8a83d0112b5bfb5a8624f7f0f81057c73e4707729cdd8077166c6aefb3d8e2b92c63ee130d4a2ff94bad46d547e12f3238cc1d78342a973841
+ languageName: node
+ linkType: hard
+
"cheerio-select@npm:^2.1.0":
version: 2.1.0
resolution: "cheerio-select@npm:2.1.0"
@@ -7234,6 +7333,15 @@ __metadata:
languageName: node
linkType: hard
+"deep-eql@npm:^4.1.3":
+ version: 4.1.4
+ resolution: "deep-eql@npm:4.1.4"
+ dependencies:
+ type-detect: "npm:^4.0.0"
+ checksum: 10c0/264e0613493b43552fc908f4ff87b8b445c0e6e075656649600e1b8a17a57ee03e960156fce7177646e4d2ddaf8e5ee616d76bd79929ff593e5c79e4e5e6c517
+ languageName: node
+ linkType: hard
+
"deep-extend@npm:^0.6.0":
version: 0.6.0
resolution: "deep-extend@npm:0.6.0"
@@ -8007,7 +8115,7 @@ __metadata:
languageName: node
linkType: hard
-"esbuild@npm:^0.21.4":
+"esbuild@npm:^0.21.3, esbuild@npm:^0.21.4":
version: 0.21.5
resolution: "esbuild@npm:0.21.5"
dependencies:
@@ -8366,7 +8474,7 @@ __metadata:
languageName: node
linkType: hard
-"estree-walker@npm:^3.0.0":
+"estree-walker@npm:^3.0.0, estree-walker@npm:^3.0.3":
version: 3.0.3
resolution: "estree-walker@npm:3.0.3"
dependencies:
@@ -8995,6 +9103,13 @@ __metadata:
languageName: node
linkType: hard
+"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "get-func-name@npm:2.0.2"
+ checksum: 10c0/89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df
+ languageName: node
+ linkType: hard
+
"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4":
version: 1.2.4
resolution: "get-intrinsic@npm:1.2.4"
@@ -10709,6 +10824,13 @@ __metadata:
languageName: node
linkType: hard
+"js-tokens@npm:^9.0.0":
+ version: 9.0.0
+ resolution: "js-tokens@npm:9.0.0"
+ checksum: 10c0/4ad1c12f47b8c8b2a3a99e29ef338c1385c7b7442198a425f3463f3537384dab6032012791bfc2f056ea5ecdb06b1ed4f70e11a3ab3f388d3dcebfe16a52b27d
+ languageName: node
+ linkType: hard
+
"js-yaml@npm:^3.10.0, js-yaml@npm:^3.13.1":
version: 3.14.1
resolution: "js-yaml@npm:3.14.1"
@@ -11019,6 +11141,16 @@ __metadata:
languageName: node
linkType: hard
+"local-pkg@npm:^0.5.0":
+ version: 0.5.0
+ resolution: "local-pkg@npm:0.5.0"
+ dependencies:
+ mlly: "npm:^1.4.2"
+ pkg-types: "npm:^1.0.3"
+ checksum: 10c0/f61cbd00d7689f275558b1a45c7ff2a3ddf8472654123ed880215677b9adfa729f1081e50c27ffb415cdb9fa706fb755fec5e23cdd965be375c8059e87ff1cc9
+ languageName: node
+ linkType: hard
+
"locate-path@npm:^3.0.0":
version: 3.0.0
resolution: "locate-path@npm:3.0.0"
@@ -11143,6 +11275,15 @@ __metadata:
languageName: node
linkType: hard
+"loupe@npm:^2.3.6, loupe@npm:^2.3.7":
+ version: 2.3.7
+ resolution: "loupe@npm:2.3.7"
+ dependencies:
+ get-func-name: "npm:^2.0.1"
+ checksum: 10c0/71a781c8fc21527b99ed1062043f1f2bb30bdaf54fa4cf92463427e1718bc6567af2988300bc243c1f276e4f0876f29e3cbf7b58106fdc186915687456ce5bf4
+ languageName: node
+ linkType: hard
+
"lower-case@npm:^2.0.2":
version: 2.0.2
resolution: "lower-case@npm:2.0.2"
@@ -11182,6 +11323,15 @@ __metadata:
languageName: node
linkType: hard
+"magic-string@npm:^0.30.5":
+ version: 0.30.10
+ resolution: "magic-string@npm:0.30.10"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.4.15"
+ checksum: 10c0/aa9ca17eae571a19bce92c8221193b6f93ee8511abb10f085e55ffd398db8e4c089a208d9eac559deee96a08b7b24d636ea4ab92f09c6cf42a7d1af51f7fd62b
+ languageName: node
+ linkType: hard
+
"make-fetch-happen@npm:^13.0.0":
version: 13.0.1
resolution: "make-fetch-happen@npm:13.0.1"
@@ -12288,7 +12438,7 @@ __metadata:
languageName: node
linkType: hard
-"mlly@npm:^1.6.1, mlly@npm:^1.7.0":
+"mlly@npm:^1.4.2, mlly@npm:^1.6.1, mlly@npm:^1.7.0":
version: 1.7.1
resolution: "mlly@npm:1.7.1"
dependencies:
@@ -12925,6 +13075,15 @@ __metadata:
languageName: node
linkType: hard
+"p-limit@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "p-limit@npm:5.0.0"
+ dependencies:
+ yocto-queue: "npm:^1.0.0"
+ checksum: 10c0/574e93b8895a26e8485eb1df7c4b58a1a6e8d8ae41b1750cc2cc440922b3d306044fc6e9a7f74578a883d46802d9db72b30f2e612690fcef838c173261b1ed83
+ languageName: node
+ linkType: hard
+
"p-locate@npm:^3.0.0":
version: 3.0.0
resolution: "p-locate@npm:3.0.0"
@@ -13203,6 +13362,13 @@ __metadata:
languageName: node
linkType: hard
+"pathval@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "pathval@npm:1.1.1"
+ checksum: 10c0/f63e1bc1b33593cdf094ed6ff5c49c1c0dc5dc20a646ca9725cc7fe7cd9995002d51d5685b9b2ec6814342935748b711bafa840f84c0bb04e38ff40a335c94dc
+ languageName: node
+ linkType: hard
+
"periscopic@npm:^3.0.0":
version: 3.1.0
resolution: "periscopic@npm:3.1.0"
@@ -13282,7 +13448,7 @@ __metadata:
languageName: node
linkType: hard
-"pkg-types@npm:^1.1.1":
+"pkg-types@npm:^1.0.3, pkg-types@npm:^1.1.1":
version: 1.1.1
resolution: "pkg-types@npm:1.1.1"
dependencies:
@@ -15274,6 +15440,13 @@ __metadata:
languageName: node
linkType: hard
+"siginfo@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "siginfo@npm:2.0.0"
+ checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34
+ languageName: node
+ linkType: hard
+
"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3":
version: 3.0.7
resolution: "signal-exit@npm:3.0.7"
@@ -15595,6 +15768,13 @@ __metadata:
languageName: node
linkType: hard
+"stackback@npm:0.0.2":
+ version: 0.0.2
+ resolution: "stackback@npm:0.0.2"
+ checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983
+ languageName: node
+ linkType: hard
+
"statuses@npm:2.0.1":
version: 2.0.1
resolution: "statuses@npm:2.0.1"
@@ -15609,7 +15789,7 @@ __metadata:
languageName: node
linkType: hard
-"std-env@npm:^3.0.1, std-env@npm:^3.7.0":
+"std-env@npm:^3.0.1, std-env@npm:^3.5.0, std-env@npm:^3.7.0":
version: 3.7.0
resolution: "std-env@npm:3.7.0"
checksum: 10c0/60edf2d130a4feb7002974af3d5a5f3343558d1ccf8d9b9934d225c638606884db4a20d2fe6440a09605bca282af6b042ae8070a10490c0800d69e82e478f41e
@@ -15823,6 +16003,15 @@ __metadata:
languageName: node
linkType: hard
+"strip-literal@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "strip-literal@npm:2.1.0"
+ dependencies:
+ js-tokens: "npm:^9.0.0"
+ checksum: 10c0/bc8b8c8346125ae3c20fcdaf12e10a498ff85baf6f69597b4ab2b5fbf2e58cfd2827f1a44f83606b852da99a5f6c8279770046ddea974c510c17c98934c9cc24
+ languageName: node
+ linkType: hard
+
"strong-log-transformer@npm:^2.1.0":
version: 2.1.0
resolution: "strong-log-transformer@npm:2.1.0"
@@ -16088,6 +16277,27 @@ __metadata:
languageName: node
linkType: hard
+"tinybench@npm:^2.5.1":
+ version: 2.8.0
+ resolution: "tinybench@npm:2.8.0"
+ checksum: 10c0/5a9a642351fa3e4955e0cbf38f5674be5f3ba6730fd872fd23a5c953ad6c914234d5aba6ea41ef88820180a81829ceece5bd8d3967c490c5171bca1141c2f24d
+ languageName: node
+ linkType: hard
+
+"tinypool@npm:^0.8.3":
+ version: 0.8.4
+ resolution: "tinypool@npm:0.8.4"
+ checksum: 10c0/779c790adcb0316a45359652f4b025958c1dff5a82460fe49f553c864309b12ad732c8288be52f852973bc76317f5e7b3598878aee0beb8a33322c0e72c4a66c
+ languageName: node
+ linkType: hard
+
+"tinyspy@npm:^2.2.0":
+ version: 2.2.1
+ resolution: "tinyspy@npm:2.2.1"
+ checksum: 10c0/0b4cfd07c09871e12c592dfa7b91528124dc49a4766a0b23350638c62e6a483d5a2a667de7e6282246c0d4f09996482ddaacbd01f0c05b7ed7e0f79d32409bdc
+ languageName: node
+ linkType: hard
+
"tmp@npm:~0.2.1":
version: 0.2.3
resolution: "tmp@npm:0.2.3"
@@ -16262,6 +16472,13 @@ __metadata:
languageName: node
linkType: hard
+"type-detect@npm:^4.0.0, type-detect@npm:^4.0.8":
+ version: 4.0.8
+ resolution: "type-detect@npm:4.0.8"
+ checksum: 10c0/8fb9a51d3f365a7de84ab7f73b653534b61b622aa6800aecdb0f1095a4a646d3f5eb295322127b6573db7982afcd40ab492d038cf825a42093a58b1e1353e0bd
+ languageName: node
+ linkType: hard
+
"type-fest@npm:^1.0.1":
version: 1.4.0
resolution: "type-fest@npm:1.4.0"
@@ -16905,6 +17122,61 @@ __metadata:
languageName: node
linkType: hard
+"vite-node@npm:1.6.0":
+ version: 1.6.0
+ resolution: "vite-node@npm:1.6.0"
+ dependencies:
+ cac: "npm:^6.7.14"
+ debug: "npm:^4.3.4"
+ pathe: "npm:^1.1.1"
+ picocolors: "npm:^1.0.0"
+ vite: "npm:^5.0.0"
+ bin:
+ vite-node: vite-node.mjs
+ checksum: 10c0/0807e6501ac7763e0efa2b4bd484ce99fb207e92c98624c9f8999d1f6727ac026e457994260fa7fdb7060d87546d197081e46a705d05b0136a38b6f03715cbc2
+ languageName: node
+ linkType: hard
+
+"vite@npm:^5.0.0":
+ version: 5.3.0
+ resolution: "vite@npm:5.3.0"
+ dependencies:
+ esbuild: "npm:^0.21.3"
+ fsevents: "npm:~2.3.3"
+ postcss: "npm:^8.4.38"
+ rollup: "npm:^4.13.0"
+ peerDependencies:
+ "@types/node": ^18.0.0 || >=20.0.0
+ less: "*"
+ lightningcss: ^1.21.0
+ sass: "*"
+ stylus: "*"
+ sugarss: "*"
+ terser: ^5.4.0
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ bin:
+ vite: bin/vite.js
+ checksum: 10c0/d07e1a2ce713d3f73cb83f6289c9ff320da5953f37c35edb8c1388d610e8ca1c98edd642d5c3f163f8771dae294d3d430356a09285e344f0de9fa4b058c541f0
+ languageName: node
+ linkType: hard
+
"vite@npm:^5.2.13":
version: 5.2.13
resolution: "vite@npm:5.2.13"
@@ -16945,6 +17217,56 @@ __metadata:
languageName: node
linkType: hard
+"vitest@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "vitest@npm:1.6.0"
+ dependencies:
+ "@vitest/expect": "npm:1.6.0"
+ "@vitest/runner": "npm:1.6.0"
+ "@vitest/snapshot": "npm:1.6.0"
+ "@vitest/spy": "npm:1.6.0"
+ "@vitest/utils": "npm:1.6.0"
+ acorn-walk: "npm:^8.3.2"
+ chai: "npm:^4.3.10"
+ debug: "npm:^4.3.4"
+ execa: "npm:^8.0.1"
+ local-pkg: "npm:^0.5.0"
+ magic-string: "npm:^0.30.5"
+ pathe: "npm:^1.1.1"
+ picocolors: "npm:^1.0.0"
+ std-env: "npm:^3.5.0"
+ strip-literal: "npm:^2.0.0"
+ tinybench: "npm:^2.5.1"
+ tinypool: "npm:^0.8.3"
+ vite: "npm:^5.0.0"
+ vite-node: "npm:1.6.0"
+ why-is-node-running: "npm:^2.2.2"
+ peerDependencies:
+ "@edge-runtime/vm": "*"
+ "@types/node": ^18.0.0 || >=20.0.0
+ "@vitest/browser": 1.6.0
+ "@vitest/ui": 1.6.0
+ happy-dom: "*"
+ jsdom: "*"
+ peerDependenciesMeta:
+ "@edge-runtime/vm":
+ optional: true
+ "@types/node":
+ optional: true
+ "@vitest/browser":
+ optional: true
+ "@vitest/ui":
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ bin:
+ vitest: vitest.mjs
+ checksum: 10c0/065da5b8ead51eb174d93dac0cd50042ca9539856dc25e340ea905d668c41961f7e00df3e388e6c76125b2c22091db2e8465f993d0f6944daf9598d549e562e7
+ languageName: node
+ linkType: hard
+
"vscode-oniguruma@npm:^1.7.0":
version: 1.7.0
resolution: "vscode-oniguruma@npm:1.7.0"
@@ -17298,6 +17620,18 @@ __metadata:
languageName: node
linkType: hard
+"why-is-node-running@npm:^2.2.2":
+ version: 2.2.2
+ resolution: "why-is-node-running@npm:2.2.2"
+ dependencies:
+ siginfo: "npm:^2.0.0"
+ stackback: "npm:0.0.2"
+ bin:
+ why-is-node-running: cli.js
+ checksum: 10c0/805d57eb5d33f0fb4e36bae5dceda7fd8c6932c2aeb705e30003970488f1a2bc70029ee64be1a0e1531e2268b11e65606e88e5b71d667ea745e6dc48fc9014bd
+ languageName: node
+ linkType: hard
+
"widest-line@npm:^4.0.1":
version: 4.0.1
resolution: "widest-line@npm:4.0.1"