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,