Skip to content

Commit 89b2ece

Browse files
authored
Namadillo: Phase 2 - Claim Rewards + useTransaction (#1100)
* feat(namadillo): creating useBalances hook * feat(namadillo): separating colors and other props from tailwind config * feat(components): adding label property to PieChart * feat: refactoring balance props to be reused between staking and overview * feat(namadillo): fixing overview chart * feat(namadillo): adding mocks for useBalance * feat(namadillo): adding tests for NamBalanceContainer * feat(namadillo): adding footer to AccountOverview * feat(namadillo): replacing by Panel component * feat(namadillo): claim rewards component * feat(namadillo): enabling staking rewards * temp: claiming rewards wip * feat(namadillo): adding useTransaction hook and refactoring claim rewards * refactor(namadillo): applying useTransaction to IncrementBonding * feat(namadillo): adding useTransaction on Unstake flow * feat(namadillo): applying useTransaction to redelegate * chore: fixing some merge conflicts * feat(namadillo): applying useTransaction to Withdraw * feat(namadillo): writing tests for StakingRewardsPanel * feat(namadillo): adding claim and stake * feat(namadillo): writing tests for StakingRewards * fix(namadillo): fixing staking rewards not updating
1 parent 94b6ec6 commit 89b2ece

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1562
-634
lines changed

apps/extension/src/Approvals/Commitment.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { TxType } from "@heliax/namada-sdk/web";
22
import {
33
BondProps,
4+
ClaimRewardsProps,
45
CommitmentDetailProps,
56
RedelegateProps,
67
RevealPkProps,
@@ -103,7 +104,12 @@ const renderContent = (tx: CommitmentDetailProps): ReactNode => {
103104
<>Reveal public key for address {formatAddress(revealTx.publicKey)}</>
104105
);
105106

107+
case TxType.ClaimRewards:
108+
const claimTx = tx as ClaimRewardsProps;
109+
return <>Claiming rewards from {formatAddress(claimTx.validator)}</>;
110+
106111
// TODO: continue implementing other types in the next phases
112+
107113
default:
108114
return <></>;
109115
}

apps/namadillo/jest.config.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@ module.exports = {
1010
modulePathIgnorePatterns: ["e2e-tests"],
1111
moduleDirectories: ["src", "node_modules"],
1212
verbose: true,
13-
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
14-
prefix: "<rootDir>/src/",
15-
}),
13+
moduleNameMapper: {
14+
...pathsToModuleNameMapper(compilerOptions.paths, {
15+
prefix: "<rootDir>/src/",
16+
}),
17+
"^.+\\.svg$": "jest-transformer-svg",
18+
"\\.css": "identity-obj-proxy",
19+
},
1620
setupFilesAfterEnv: ["<rootDir>/src/setupTests.ts"],
1721
};

apps/namadillo/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"test:watch": "yarn wasm:build:test && yarn jest --watchAll=true",
5858
"test:coverage": "yarn wasm:build:test && yarn test --coverage",
5959
"test:ci": "jest",
60+
"test:watch-only": "yarn jest --watchAll=true",
6061
"e2e-test": "PLAYWRIGHT_BASE_URL=http://localhost:3000 yarn playwright test",
6162
"e2e-test:headed": "PLAYWRIGHT_BASE_URL=http://localhost:3000 yarn playwright test --project=chromium --headed",
6263
"wasm:build": "node ./scripts/build.js --release",
@@ -106,10 +107,12 @@
106107
"eslint-plugin-react-hooks": "^4.6.0",
107108
"globals": "^15.9.0",
108109
"history": "^5.3.0",
110+
"identity-obj-proxy": "^3.0.0",
109111
"jest": "^29.7.0",
110112
"jest-create-mock-instance": "^2.0.0",
111113
"jest-environment-jsdom": "^29.7.0",
112114
"jest-fetch-mock": "^3.0.3",
115+
"jest-transformer-svg": "^2.0.2",
113116
"local-cors-proxy": "^1.1.0",
114117
"postcss": "^8.4.32",
115118
"release-it": "^17.0.1",

apps/namadillo/src/App/AccountOverview/AccountOverview.tsx

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,61 @@
1-
import { Stack } from "@namada/components";
1+
import { Panel, Stack } from "@namada/components";
22
import { Intro } from "App/Common/Intro";
33
import { PageWithSidebar } from "App/Common/PageWithSidebar";
44
import MainnetRoadmap from "App/Sidebars/MainnetRoadmap";
5-
import { namadaExtensionConnectedAtom } from "atoms/settings";
5+
import { StakingRewardsPanel } from "App/Staking/StakingRewardsPanel";
6+
import {
7+
applicationFeaturesAtom,
8+
namadaExtensionConnectedAtom,
9+
} from "atoms/settings";
610
import clsx from "clsx";
711
import { useAtomValue } from "jotai";
812
import { AccountBalanceContainer } from "./AccountBalanceContainer";
13+
import { NamBalanceContainer } from "./NamBalanceContainer";
914
import { NavigationFooter } from "./NavigationFooter";
1015

1116
export const AccountOverview = (): JSX.Element => {
1217
const isConnected = useAtomValue(namadaExtensionConnectedAtom);
18+
const { claimRewardsEnabled, maspEnabled } = useAtomValue(
19+
applicationFeaturesAtom
20+
);
21+
22+
const fullView = claimRewardsEnabled || maspEnabled;
1323
const fullWidthClassName = clsx({ "col-span-2": !isConnected });
24+
1425
return (
1526
<PageWithSidebar>
16-
<div
17-
className={clsx(
18-
"flex items-center bg-black rounded-sm w-full",
19-
fullWidthClassName
20-
)}
21-
>
27+
<div className={clsx("flex w-full", fullWidthClassName)}>
2228
{!isConnected && (
23-
<div className="w-[420px] mx-auto">
24-
<Intro />
25-
</div>
29+
<section className="flex rounded-sm items-center w-full bg-black">
30+
<div className="w-[420px] mx-auto">
31+
<Intro />
32+
</div>
33+
</section>
2634
)}
27-
{isConnected && (
28-
<Stack gap={5} className="my-auto min-w-[365px] mx-auto py-12">
29-
<AccountBalanceContainer />
30-
<NavigationFooter />
31-
</Stack>
35+
36+
{isConnected && !fullView && (
37+
<section className="flex items-center bg-black rounded-sm w-full">
38+
<Stack gap={5} className="my-auto min-w-[365px] mx-auto py-12">
39+
<AccountBalanceContainer />
40+
<NavigationFooter />
41+
</Stack>
42+
</section>
43+
)}
44+
45+
{isConnected && fullView && (
46+
<section className="flex flex-col w-full rounded-sm min-h-full gap-2">
47+
<div className="grid grid-cols-[1.25fr_1fr] gap-2">
48+
<Panel className="pl-4 pr-6 py-5">
49+
<NamBalanceContainer />
50+
</Panel>
51+
<Panel>
52+
<StakingRewardsPanel />
53+
</Panel>
54+
</div>
55+
<Panel className="flex items-center flex-1 justify-center">
56+
<NavigationFooter />
57+
</Panel>
58+
</section>
3259
)}
3360
</div>
3461
{isConnected && (
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { Stack } from "@namada/components";
2+
import { AtomErrorBoundary } from "App/Common/AtomErrorBoundary";
3+
import { BalanceChart } from "App/Common/BalanceChart";
4+
import { NamCurrency } from "App/Common/NamCurrency";
5+
import BigNumber from "bignumber.js";
6+
import { useBalances } from "hooks/useBalances";
7+
import { colors } from "theme";
8+
9+
type NamBalanceListItemProps = {
10+
title: string;
11+
color: string;
12+
amount: BigNumber;
13+
};
14+
15+
const NamBalanceListItem = ({
16+
title,
17+
color,
18+
amount,
19+
}: NamBalanceListItemProps): JSX.Element => {
20+
return (
21+
<li
22+
className="leading-5 bg-neutral-900 px-4 py-3 rounded-sm min-w-[165px]"
23+
aria-description={`${title} amount is ${amount.toString()} NAM`}
24+
>
25+
<span className="flex items-center text-xs gap-1.5">
26+
<i className="w-2 h-2 rounded-full" style={{ background: color }} />
27+
{title}
28+
</span>
29+
<NamCurrency
30+
amount={amount}
31+
className="text-lg pl-3.5"
32+
currencySignClassName="hidden"
33+
/>
34+
</li>
35+
);
36+
};
37+
38+
export const NamBalanceContainer = (): JSX.Element => {
39+
const {
40+
balanceQuery,
41+
stakeQuery,
42+
isLoading,
43+
isSuccess,
44+
availableAmount,
45+
bondedAmount,
46+
shieldedAmount,
47+
unbondedAmount,
48+
withdrawableAmount,
49+
totalAmount,
50+
} = useBalances();
51+
52+
return (
53+
<div className="flex gap-4 text-white">
54+
<AtomErrorBoundary
55+
result={[balanceQuery, stakeQuery]}
56+
niceError="Unable to load balances"
57+
>
58+
<div className="flex items-center w-full">
59+
<BalanceChart
60+
view="total"
61+
isLoading={isLoading}
62+
isSuccess={isSuccess}
63+
availableAmount={availableAmount}
64+
bondedAmount={bondedAmount}
65+
shieldedAmount={shieldedAmount}
66+
unbondedAmount={unbondedAmount}
67+
withdrawableAmount={withdrawableAmount}
68+
totalAmount={totalAmount}
69+
/>
70+
<Stack gap={2} as="ul">
71+
<NamBalanceListItem
72+
title="Available NAM"
73+
color={colors.balance}
74+
amount={availableAmount}
75+
/>
76+
<NamBalanceListItem
77+
title="Staked NAM"
78+
color={colors.bond}
79+
amount={bondedAmount}
80+
/>
81+
<NamBalanceListItem
82+
title="Unbonded NAM"
83+
color={colors.unbond}
84+
amount={unbondedAmount.plus(withdrawableAmount)}
85+
/>
86+
</Stack>
87+
</div>
88+
</AtomErrorBoundary>
89+
</div>
90+
);
91+
};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { cleanup, render, screen } from "@testing-library/react";
2+
import BigNumber from "bignumber.js";
3+
import { mockUseBalances } from "hooks/__mocks__/mockUseBalance";
4+
import { AtomWithQueryResult } from "jotai-tanstack-query";
5+
import { NamBalanceContainer } from "../NamBalanceContainer";
6+
7+
jest.mock("hooks/useBalances", () => ({
8+
useBalances: jest.fn(),
9+
}));
10+
11+
describe("Component: NamBalanceContainer", () => {
12+
beforeEach(() => {
13+
jest.clearAllMocks();
14+
});
15+
16+
test("renders error boundary when queries fail", () => {
17+
// Check if the error message from AtomErrorBoundary is displayed
18+
const execute = (
19+
balanceQueryError: boolean,
20+
stakeQueryError: boolean
21+
): void => {
22+
mockUseBalances({
23+
balanceQuery: { isError: balanceQueryError } as AtomWithQueryResult,
24+
stakeQuery: { isError: stakeQueryError } as AtomWithQueryResult,
25+
isLoading: false,
26+
isSuccess: false,
27+
});
28+
render(<NamBalanceContainer />);
29+
expect(screen.getByText(/Unable to load balances/i)).toBeInTheDocument();
30+
cleanup();
31+
jest.clearAllMocks();
32+
};
33+
34+
execute(true, true);
35+
execute(false, true);
36+
execute(true, false);
37+
});
38+
39+
test("renders balance items when data is loaded", () => {
40+
mockUseBalances({
41+
availableAmount: new BigNumber(100),
42+
bondedAmount: new BigNumber(50),
43+
unbondedAmount: new BigNumber(30),
44+
withdrawableAmount: new BigNumber(25),
45+
totalAmount: new BigNumber(200),
46+
});
47+
48+
render(<NamBalanceContainer />);
49+
50+
// Check if the list items for each balance type are rendered
51+
expect(screen.getByText(/Available NAM/i)).toBeInTheDocument();
52+
expect(screen.getByText(/Staked NAM/i)).toBeInTheDocument();
53+
expect(screen.getByText(/Unbonded NAM/i)).toBeInTheDocument();
54+
55+
// Check if the amounts are displayed correctly
56+
57+
// Available:
58+
expect(screen.getByText("100 NAM")).toBeInTheDocument();
59+
60+
// Bonded / Staked
61+
expect(screen.getByText("50 NAM")).toBeInTheDocument();
62+
63+
// Unbonded + Withdraw
64+
expect(screen.queryByText("30 NAM")).toBeNull();
65+
expect(screen.queryByText("25 NAM")).toBeNull();
66+
expect(screen.getByText("55 NAM")).toBeInTheDocument();
67+
});
68+
});

apps/namadillo/src/App/AppRoutes.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import GovernanceRoutes from "./Governance/routes";
1919
import SettingsRoutes from "./Settings/routes";
2020
import { SignMessages } from "./SignMessages/SignMessages";
2121
import MessageRoutes from "./SignMessages/routes";
22+
import { StakingRewards } from "./Staking/StakingRewards";
2223
import StakingRoutes from "./Staking/routes";
2324
import SwitchAccountRoutes from "./SwitchAccount/routes";
2425

@@ -60,6 +61,10 @@ export const MainRoutes = (): JSX.Element => {
6061
element={<SignMessages />}
6162
errorElement={<RouteErrorBoundary />}
6263
/>
64+
<Route
65+
path={`${StakingRoutes.claimRewards().url}`}
66+
element={<StakingRewards />}
67+
/>
6368
</Routes>
6469
<ScrollRestoration />
6570
</>

0 commit comments

Comments
 (0)