diff --git a/.changeset/fair-yaks-type.md b/.changeset/fair-yaks-type.md
new file mode 100644
index 00000000..0ed837c7
--- /dev/null
+++ b/.changeset/fair-yaks-type.md
@@ -0,0 +1,5 @@
+---
+"@reactive-dot/react": minor
+---
+
+Add hooks for converting planck or number to native token amount.
diff --git a/apps/docs/docs/getting-started/number-utility.md b/apps/docs/docs/getting-started/number-utility.md
index e865a4a0..de9e50c8 100644
--- a/apps/docs/docs/getting-started/number-utility.md
+++ b/apps/docs/docs/getting-started/number-utility.md
@@ -46,3 +46,27 @@ dotAmount = dotAmount.mapFromNumber((number) => (number * 2) / 4);
console.log(dotAmount.toLocaleString()); // DOT 5.25
```
+
+## Native token
+
+Two hooks [`useNativeTokenAmountFromPlanck`](/api/react/function/useNativeTokenAmountFromPlanck) & [`useNativeTokenAmountFromNumber`](/api/react/function/useNativeTokenAmountFromNumber) are also provided for easy conversion from planck and number value.
+
+```ts
+let amount = useNativeTokenAmountFromPlanck(10_000_000_000n);
+// Or
+amount = useNativeTokenAmountFromNumber(1);
+
+console.log(amount.toLocaleString("en-NZ")); // DOT 1.00
+
+// Partial application is also supported by omitting the planck/number value.
+// Here, a conversion function will be returned instead.
+const amountFromPlanck = useNativeTokenAmountFromPlanck();
+
+[10_000_000_000n, 20_000_000_000n, 30_000_000_000n]
+ .map(amountFromPlanck)
+ .map((amount) => amount.toLocaleString("en-NZ"))
+ .forEach(console.log);
+// DOT 1.00
+// DOT 2.00
+// DOT 3.00
+```
diff --git a/apps/example/src/app.tsx b/apps/example/src/app.tsx
index dec1285d..7628d9d0 100644
--- a/apps/example/src/app.tsx
+++ b/apps/example/src/app.tsx
@@ -6,39 +6,28 @@ import {
ReDotProvider,
useAccounts,
useBlock,
- useChainSpecData,
useConnectWallet,
useConnectedWallets,
useDisconnectWallet,
- useMutation,
useLazyLoadQuery,
useLazyLoadQueryWithRefresh,
+ useMutation,
+ useMutationEffect,
+ useNativeTokenAmountFromPlanck,
useResetQueryError,
useWallets,
- useMutationEffect,
} 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";
import toast, { Toaster } from "react-hot-toast";
-function useNativeTokenNumberWithPlanck(planck: bigint) {
- const chainSpecData = useChainSpecData();
-
- return new DenominatedNumber(
- planck,
- chainSpecData.properties.tokenDecimals,
- chainSpecData.properties.tokenSymbol,
- );
-}
-
function PendingRewards(props: { address: string; rewards: bigint }) {
return (
{props.address}:{" "}
- {useNativeTokenNumberWithPlanck(props.rewards).toLocaleString()}
+ {useNativeTokenAmountFromPlanck(props.rewards).toLocaleString()}
);
}
@@ -143,7 +132,7 @@ function Query() {
Total issuance
- {useNativeTokenNumberWithPlanck(totalIssuance).toLocaleString()}
+ {useNativeTokenAmountFromPlanck(totalIssuance).toLocaleString()}
Bonding duration
@@ -152,7 +141,7 @@ function Query() {
Total value staked
- {useNativeTokenNumberWithPlanck(
+ {useNativeTokenAmountFromPlanck(
typeof totalStaked === "bigint" ? totalStaked : 0n,
).toLocaleString()}
@@ -160,7 +149,7 @@ function Query() {
Total value locked in nomination Pools
- {useNativeTokenNumberWithPlanck(totalValueLocked).toLocaleString()}
+ {useNativeTokenAmountFromPlanck(totalValueLocked).toLocaleString()}
diff --git a/packages/react/src/hooks/use-native-token-amount.ts b/packages/react/src/hooks/use-native-token-amount.ts
new file mode 100644
index 00000000..bc2faa0d
--- /dev/null
+++ b/packages/react/src/hooks/use-native-token-amount.ts
@@ -0,0 +1,100 @@
+import type { ChainHookOptions } from "./types.js";
+import { useChainSpecData } from "./use-chain-spec-data.js";
+import { DenominatedNumber } from "@reactive-dot/utils";
+
+/**
+ * Hook for returning the native token amount from a planck value
+ *
+ * @param planck - The planck value
+ * @param options - Additional options
+ * @returns The native token amount
+ */
+export function useNativeTokenAmountFromPlanck(
+ planck: bigint,
+ options?: ChainHookOptions,
+): DenominatedNumber;
+/**
+ * Hook for returning a function that converts planck value to native token amount
+ *
+ * @param options - Additional options
+ * @returns Function for getting the native token amount from a planck value
+ */
+export function useNativeTokenAmountFromPlanck(
+ options?: ChainHookOptions,
+): (planck: bigint | number | string) => DenominatedNumber;
+export function useNativeTokenAmountFromPlanck(
+ planckOrOptions?: bigint | number | string | ChainHookOptions,
+ maybeOptions?: ChainHookOptions,
+):
+ | DenominatedNumber
+ | ((planck: bigint | number | string) => DenominatedNumber) {
+ const options =
+ typeof planckOrOptions === "object" ? planckOrOptions : maybeOptions;
+
+ const chainSpecData = useChainSpecData(options);
+
+ switch (typeof planckOrOptions) {
+ case "bigint":
+ case "number":
+ case "string":
+ return new DenominatedNumber(
+ planckOrOptions,
+ chainSpecData.properties.tokenDecimals,
+ chainSpecData.properties.tokenSymbol,
+ );
+ default:
+ return (planck: bigint | number | string) =>
+ new DenominatedNumber(
+ planck,
+ chainSpecData.properties.tokenDecimals,
+ chainSpecData.properties.tokenSymbol,
+ );
+ }
+}
+
+/**
+ * Hook for returning the native token amount from a number value
+ *
+ * @param planck - The number value
+ * @param options - Additional options
+ * @returns The native token amount
+ */
+export function useNativeTokenAmountFromNumber(
+ number: number | string,
+ options?: ChainHookOptions,
+): DenominatedNumber;
+/**
+ * Hook for returning a function that converts number value to native token amount
+ *
+ * @param options - Additional options
+ * @returns Function for getting the native token amount from a number value
+ */
+export function useNativeTokenAmountFromNumber(
+ options?: ChainHookOptions,
+): (number: number | string) => DenominatedNumber;
+export function useNativeTokenAmountFromNumber(
+ numberOrOptions?: number | string | ChainHookOptions,
+ maybeOptions?: ChainHookOptions,
+): DenominatedNumber | ((planck: number) => DenominatedNumber) {
+ const options =
+ typeof numberOrOptions === "object" ? numberOrOptions : maybeOptions;
+
+ const chainSpecData = useChainSpecData(options);
+
+ switch (typeof numberOrOptions) {
+ case "number":
+ case "string":
+ return new DenominatedNumber(
+ numberOrOptions,
+ chainSpecData.properties.tokenDecimals,
+ chainSpecData.properties.tokenSymbol,
+ );
+ default:
+ return (number: number) =>
+ DenominatedNumber.fromNumber(
+ number,
+ chainSpecData.properties.tokenDecimals,
+ chainSpecData.properties.tokenSymbol,
+ );
+ }
+}
diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts
index 41e2f2ad..19922e60 100644
--- a/packages/react/src/index.ts
+++ b/packages/react/src/index.ts
@@ -16,6 +16,10 @@ export { useConnectWallet } from "./hooks/use-connect-wallet.js";
export { useDisconnectWallet } from "./hooks/use-disconnect-wallet.js";
export { useMutationEffect } from "./hooks/use-mutation-effect.js";
export { useMutation } from "./hooks/use-mutation.js";
+export {
+ useNativeTokenAmountFromNumber,
+ useNativeTokenAmountFromPlanck,
+} from "./hooks/use-native-token-amount.js";
export {
useLazyLoadQuery,
useLazyLoadQueryWithRefresh,