Skip to content

Commit

Permalink
Feat: Add mana units (#1262)
Browse files Browse the repository at this point in the history
* feat: Add hardcoded manaUnits and use it in AddressBalance to format mana

* feat: Extend formatAmount to support bigint and string values. Add more format amount unit tests.

* chore: Add more tests for valueFormatHelper for all types

* feat: Add formatting to blockIssuanceCredits and manaRewards

* feat: Fix error with changed formatAmount

* feat: Cover some edge cases in valueFormat

* fix: remove comment

---------

Co-authored-by: Branko Bosnic <[email protected]>
  • Loading branch information
msarcev and brancoder authored Mar 7, 2024
1 parent 9362bbe commit d651fa4
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 113 deletions.
3 changes: 2 additions & 1 deletion client/src/app/AppUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { IOTA_UI, Theme } from "~models/config/uiTheme";
import { IStardustNodeInfo } from "~services/stardust/nodeInfoService";
import { ServiceFactory } from "~/factories/serviceFactory";
import { NodeInfoService as NodeInfoServiceNova } from "~services/nova/nodeInfoService";
import { useNetworkInfoNova } from "~/helpers/nova/networkInfo";
import { MANA_INFO_DEFAULT, useNetworkInfoNova } from "~/helpers/nova/networkInfo";
import { NavigationRoute } from "./lib/interfaces";
import { InfoResponse } from "@iota/sdk-wasm-nova/web";

Expand Down Expand Up @@ -167,6 +167,7 @@ export const populateNetworkInfoNova = (networkName: string) => {
setNetworkInfoNova({
name: networkName,
tokenInfo: nodeInfo?.baseToken ?? {},
manaInfo: MANA_INFO_DEFAULT,
protocolVersion: protocolInfo?.parameters.version ?? -1,
protocolInfo,
latestConfirmedSlot: nodeInfo?.status?.latestConfirmedBlockSlot ?? -1,
Expand Down
150 changes: 90 additions & 60 deletions client/src/app/components/nova/address/AddressBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ const AddressBalance: React.FC<AddressBalanceProps> = ({
manaRewards,
storageDeposit,
}) => {
const { tokenInfo } = useNetworkInfoNova((s) => s.networkInfo);
const [formatBalanceFull, setFormatBalanceFull] = useState(false);
const { tokenInfo, manaInfo } = useNetworkInfoNova((s) => s.networkInfo);
const [formatBaseTokenBalanceFull, setFormatBaseTokenBalanceFull] = useState(false);
const [formatManaBalanceFull, setFormatManaBalanceFull] = useState(false);
const [formatConditionalBalanceFull, setFormatConditionalBalanceFull] = useState(false);
const [formatStorageBalanceFull, setFormatStorageBalanceFull] = useState(false);

Expand All @@ -61,6 +62,7 @@ const AddressBalance: React.FC<AddressBalanceProps> = ({
}

const baseTokenBalanceView = buildBaseTokenBalanceView(tokenInfo);
const manaBalanceView = buildManaBalanceView(manaInfo);

const conditionalBaseTokenBalance =
!availableBaseTokenBalance || !totalBaseTokenBalance ? undefined : totalBaseTokenBalance - availableBaseTokenBalance;
Expand All @@ -82,8 +84,8 @@ const AddressBalance: React.FC<AddressBalanceProps> = ({
<div className="balance-wrapper__base-token">
{baseTokenBalanceView(
"Available Base Token",
formatBalanceFull,
setFormatBalanceFull,
formatBaseTokenBalanceFull,
setFormatBaseTokenBalanceFull,
false,
shouldShowExtendedBalance ? availableBaseTokenBalance : totalBaseTokenBalance,
)}
Expand All @@ -100,9 +102,23 @@ const AddressBalance: React.FC<AddressBalanceProps> = ({

<div className="balance-wrapper__mana">
{(availableStoredMana !== null || availablePotentialMana !== null || blockIssuanceCredits !== null) &&
manaBalanceView("Available Mana", availableStoredMana, availablePotentialMana, blockIssuanceCredits, manaRewards)}
manaBalanceView(
"Available Mana",
formatManaBalanceFull,
setFormatManaBalanceFull,
availableStoredMana,
availablePotentialMana,
blockIssuanceCredits,
manaRewards,
)}
{(conditionalStoredMana !== null || conditionalPotentialMana !== null) &&
manaBalanceView("Conditionally Locked Mana", conditionalStoredMana, conditionalPotentialMana)}
manaBalanceView(
"Conditionally Locked Mana",
formatStorageBalanceFull,
setFormatStorageBalanceFull,
conditionalStoredMana,
conditionalPotentialMana,
)}
</div>
</div>
</div>
Expand Down Expand Up @@ -146,83 +162,97 @@ function buildBaseTokenBalanceView(tokenInfo: BaseTokenResponse) {
return baseTokenBalanceView;
}

const manaBalanceView = (
label: string,
storedMana: number | null,
potentialMana: number | null,
blockIssuanceCredits: bigint | null = null,
manaRewards: bigint | null = null,
) => (
<div className="balance">
<div className="row middle balance-heading">
<div className="label">{label}</div>
</div>
<div className="balance__mana">
<div className="label">Stored:</div>
<div className="value featured">
{storedMana !== null && storedMana > 0 ? (
<div className="balance-value middle">
<div className="row middle">
<span className="balance-base-token pointer margin-r-5">{storedMana}</span>
<CopyButton copy={String(storedMana)} />
</div>
</div>
) : (
<span className="margin-r-5">0</span>
)}
</div>
</div>
<div className="balance__mana">
<div className="label">Potential:</div>
<div className="value featured">
{potentialMana !== null && potentialMana > 0 ? (
<div className="balance-value middle">
<div className="row middle">
<span className="balance-base-token pointer margin-r-5">{potentialMana}</span>
<CopyButton copy={String(potentialMana)} />
</div>
</div>
) : (
<span className="margin-r-5">0</span>
)}
function buildManaBalanceView(manaInfo: BaseTokenResponse) {
const manaTokenBalanceView = (
label: string,
isFormatFull: boolean,
setIsFormatFull: React.Dispatch<React.SetStateAction<boolean>>,
storedMana: number | null,
potentialMana: number | null,
blockIssuanceCredits: bigint | null = null,
manaRewards: bigint | null = null,
) => (
<div className="balance">
<div className="row middle balance-heading">
<div className="label">{label}</div>
</div>
</div>
{blockIssuanceCredits !== null && (
<div className="balance__mana">
<div className="label">Block issuance credits:</div>
<div className="label">Stored:</div>
<div className="value featured">
{blockIssuanceCredits && blockIssuanceCredits > 0 ? (
{storedMana !== null && storedMana > 0 ? (
<div className="balance-value middle">
<div className="row middle">
<span className="balance-base-token pointer margin-r-5">{blockIssuanceCredits.toString()}</span>
<CopyButton copy={blockIssuanceCredits.toString()} />
<span className="balance-base-token pointer margin-r-5" onClick={() => setIsFormatFull(!isFormatFull)}>
{formatAmount(storedMana, manaInfo, isFormatFull)}
</span>
<CopyButton copy={String(storedMana)} />
</div>
</div>
) : (
<span className="margin-r-5">0</span>
)}
</div>
</div>
)}
{manaRewards !== null && (
<div className="balance__mana">
<div className="label">Mana rewards:</div>
<div className="label">Potential:</div>
<div className="value featured">
{manaRewards && manaRewards > 0 ? (
{potentialMana !== null && potentialMana > 0 ? (
<div className="balance-value middle">
<div className="row middle">
<span className="balance-base-token pointer margin-r-5">{manaRewards.toString()}</span>
<CopyButton copy={manaRewards.toString()} />
<span className="balance-base-token pointer margin-r-5" onClick={() => setIsFormatFull(!isFormatFull)}>
{formatAmount(potentialMana, manaInfo, isFormatFull)}
</span>
<CopyButton copy={String(potentialMana)} />
</div>
</div>
) : (
<span className="margin-r-5">0</span>
)}
</div>
</div>
)}
</div>
);
{blockIssuanceCredits !== null && (
<div className="balance__mana">
<div className="label">Block issuance credits:</div>
<div className="value featured">
{blockIssuanceCredits && blockIssuanceCredits > 0 ? (
<div className="balance-value middle">
<div className="row middle">
<span className="balance-base-token pointer margin-r-5" onClick={() => setIsFormatFull(!isFormatFull)}>
{formatAmount(blockIssuanceCredits.toString(), manaInfo, isFormatFull)}
</span>
<CopyButton copy={blockIssuanceCredits.toString()} />
</div>
</div>
) : (
<span className="margin-r-5">0</span>
)}
</div>
</div>
)}
{manaRewards !== null && (
<div className="balance__mana">
<div className="label">Mana rewards:</div>
<div className="value featured">
{manaRewards && manaRewards > 0 ? (
<div className="balance-value middle">
<div className="row middle">
<span className="balance-base-token pointer margin-r-5" onClick={() => setIsFormatFull(!isFormatFull)}>
{formatAmount(manaRewards.toString(), manaInfo, isFormatFull)}
</span>
<CopyButton copy={manaRewards.toString()} />
</div>
</div>
) : (
<span className="margin-r-5">0</span>
)}
</div>
</div>
)}
</div>
);

return manaTokenBalanceView;
}

AddressBalance.defaultProps = {
totalBaseTokenBalance: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ export const InfluxChartsTab: React.FC = () => {
analyticStats,
] = useChartsState();

const lockedStorageDepositValue =
formatAmount(Number(analyticStats?.lockedStorageDeposit), tokenInfo).replace(COMMAS_REGEX, ",") ?? "-";
const lockedStorageDepositValue = analyticStats?.lockedStorageDeposit
? formatAmount(analyticStats.lockedStorageDeposit, tokenInfo).replace(COMMAS_REGEX, ",")
: "-";

const ids = idGenerator();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const buildShimmerClaimedStats = (claimed: string, supply: string, tokenI

const formatFull = bigInt < Math.pow(10, tokenInfo.decimals - 3);
const decimals = bigInt < Math.pow(10, tokenInfo.decimals) ? 3 : bigInt < Math.pow(10, tokenInfo.decimals + 2) ? 2 : 0;
claimedFinal = formatAmount(Number(claimedFinal), tokenInfo, formatFull, decimals);
claimedFinal = formatAmount(claimedFinal, tokenInfo, formatFull, decimals);
claimedFinal = claimedFinal.replaceAll(COMMAS_REGEX, ",");

const claimedPercentBd = new BigDecimal("100", 2).multiply(claimedBd.toString()).divide(supply);
Expand Down
11 changes: 11 additions & 0 deletions client/src/helpers/nova/networkInfo.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { BaseTokenResponse, ProtocolParametersResponse } from "@iota/sdk-wasm-nova/web";
import { create } from "zustand";

export const MANA_INFO_DEFAULT = {
name: "Mana",
tickerSymbol: "Mana",
unit: "Mana",
decimals: 6,
subunit: "µMana",
useMetricPrefix: false,
};

interface INetworkInfo {
name: string;
tokenInfo: BaseTokenResponse;
manaInfo: BaseTokenResponse;
protocolVersion: number;
protocolInfo: ProtocolParametersResponse | null;
latestConfirmedSlot: number;
Expand All @@ -26,6 +36,7 @@ export const useNetworkInfoNova = create<NetworkInfoState>((set) => ({
subunit: undefined,
useMetricPrefix: true,
},
manaInfo: MANA_INFO_DEFAULT,
protocolVersion: -1,
protocolInfo: null,
latestConfirmedSlot: -1,
Expand Down
Loading

0 comments on commit d651fa4

Please sign in to comment.