Skip to content

Commit

Permalink
feat: hooks for getting native token amount
Browse files Browse the repository at this point in the history
  • Loading branch information
tien committed Aug 5, 2024
1 parent edfaf28 commit 21d57ad
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/fair-yaks-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@reactive-dot/react": minor
---

Add hooks for converting planck or number to native token amount.
31 changes: 31 additions & 0 deletions apps/docs/docs/guides/number-utility.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ sidebar_position: 2

# Number utility

## Denominated number

To handle complexity around [planck unit](https://wiki.polkadot.network/docs/learn-DOT#the-planck-unit) used in Polkadot, a utility class [`DenominatedNumber`](/api/utils/class/DenominatedNumber) is provided by [`@reactive-dot/utils`](https://reactivedot.dev/api/utils).

```ts
Expand Down Expand Up @@ -46,3 +48,32 @@ 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/or number value to native token amount.

```ts
import {
useNativeTokenAmountFromNumber,
useNativeTokenAmountFromPlanck,
} from "@reactive-dot/react";

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
```
25 changes: 7 additions & 18 deletions apps/example/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<li>
{props.address}:{" "}
{useNativeTokenNumberWithPlanck(props.rewards).toLocaleString()}
{useNativeTokenAmountFromPlanck(props.rewards).toLocaleString()}
</li>
);
}
Expand Down Expand Up @@ -143,7 +132,7 @@ function Query() {
</article>
<article>
<h4>Total issuance</h4>
<p>{useNativeTokenNumberWithPlanck(totalIssuance).toLocaleString()}</p>
<p>{useNativeTokenAmountFromPlanck(totalIssuance).toLocaleString()}</p>
</article>
<article>
<h4>Bonding duration</h4>
Expand All @@ -152,15 +141,15 @@ function Query() {
<article>
<h4>Total value staked</h4>
<p>
{useNativeTokenNumberWithPlanck(
{useNativeTokenAmountFromPlanck(
typeof totalStaked === "bigint" ? totalStaked : 0n,
).toLocaleString()}
</p>
</article>
<article>
<h4>Total value locked in nomination Pools</h4>
<p>
{useNativeTokenNumberWithPlanck(totalValueLocked).toLocaleString()}
{useNativeTokenAmountFromPlanck(totalValueLocked).toLocaleString()}
</p>
</article>
<article>
Expand Down
100 changes: 100 additions & 0 deletions packages/react/src/hooks/use-native-token-amount.ts
Original file line number Diff line number Diff line change
@@ -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,
);
}
}
4 changes: 4 additions & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 21d57ad

Please sign in to comment.