Skip to content

Commit 8312ccb

Browse files
authored
Merge pull request #108 from ChainSafe/irubido/shieldBalance
shield balance
2 parents ea45380 + 778b7fa commit 8312ccb

File tree

9 files changed

+207
-48
lines changed

9 files changed

+207
-48
lines changed

packages/web-wallet/src/components/NavBar/NavBar.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ArrowReceiveSvg,
77
ArrowTransferSvg,
88
SummarySvg,
9+
ShieldSvg
910
} from '../../assets';
1011

1112
interface NavItem {
@@ -24,6 +25,11 @@ const navItems: NavItem[] = [
2425
to: 'transfer-balance',
2526
label: 'Transfer Balance',
2627
icon: <ArrowTransferSvg />,
28+
},
29+
{
30+
to: 'shield-balance',
31+
label: 'Shield Balance',
32+
icon: <ShieldSvg />,
2733
},
2834
{
2935
to: 'receive',

packages/web-wallet/src/pages/TransferBalance/TransferConfirm.tsx renamed to packages/web-wallet/src/components/TransferCards/TransferConfirm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import React from 'react';
22
import {
33
TransferBalanceFormData,
44
TransferBalanceFormType,
5-
} from './useTransferBalanceForm';
6-
import Button from '../../components/Button/Button';
5+
} from '../../pages/TransferBalance/useTransferBalanceForm';
6+
import Button from '../Button/Button';
77

88
interface TransferConfirmProps {
99
formData: TransferBalanceFormData;

packages/web-wallet/src/pages/TransferBalance/TransferInput.tsx renamed to packages/web-wallet/src/components/TransferCards/TransferInput.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import React, { useState } from 'react';
22
import {
33
TransferBalanceFormData,
44
TransferBalanceFormHandleChange,
5-
} from './useTransferBalanceForm';
6-
import Input from '../../components/Input/Input';
7-
import Button from '../../components/Button/Button';
5+
} from '../../pages/TransferBalance/useTransferBalanceForm';
6+
import Input from '../Input/Input';
7+
import Button from '../Button/Button';
88

99
interface TransferInputProps {
1010
formData: TransferBalanceFormData;

packages/web-wallet/src/pages/TransferBalance/TransferResult.tsx renamed to packages/web-wallet/src/components/TransferCards/TransferResult.tsx

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,69 @@
11
import { useNavigate } from 'react-router-dom';
2-
import { TransferBalanceFormType } from './useTransferBalanceForm';
2+
import { TransferBalanceFormType } from '../../pages/TransferBalance/useTransferBalanceForm';
33
import React from 'react';
44
import { CheckSVG, WarningSVG } from '../../assets';
5-
import Button from '../../components/Button/Button';
6-
import TransactionStatusCard from '../../components/TransactionStatusCard/TransactionStatusCard';
5+
import Button from '../Button/Button';
6+
import TransactionStatusCard from '../TransactionStatusCard/TransactionStatusCard';
77
import { PcztTransferStatus } from 'src/hooks/usePCZT';
88
import Loader from 'src/components/Loader/Loader';
99

1010
interface TransferResultProps {
1111
pcztTransferStatus: PcztTransferStatus;
1212
resetForm: TransferBalanceFormType['resetForm'];
13+
isShieldTransaction?: boolean;
1314
}
1415

1516
export function TransferResult({
1617
pcztTransferStatus,
1718
resetForm,
19+
isShieldTransaction,
1820
}: TransferResultProps): React.JSX.Element {
1921
const navigate = useNavigate();
2022

23+
const actionWord = isShieldTransaction ? 'Shielding' : 'Transfer';
24+
2125
switch (pcztTransferStatus) {
2226
case PcztTransferStatus.SEND_SUCCESSFUL:
2327
return <TransactionStatusCard
24-
headText="Transfer complete"
25-
statusMessage="Your transaction has been sent."
28+
headText={`${actionWord} complete`}
29+
statusMessage={`Your transaction has been sent.`}
2630
icon={<CheckSVG />}
2731
>
2832
<Button
2933
onClick={() =>
3034
navigate('/dashboard/account-summary', { replace: true })
3135
}
32-
label={'Back to Account Summary'}
33-
/>
34-
<Button
35-
variant="secondary"
36-
classNames="border-[#0e0e0e]"
37-
onClick={() => resetForm()}
38-
label={'Make Another Transfer'}
36+
label={`Back to Account Summary`}
3937
/>
38+
{!isShieldTransaction && (
39+
<Button
40+
variant="secondary"
41+
classNames="border-[#0e0e0e]"
42+
onClick={() => resetForm()}
43+
label={'Make Another Transfer'}
44+
/>
45+
)}
4046
</TransactionStatusCard>
4147

4248
case PcztTransferStatus.SEND_ERROR:
4349
return <TransactionStatusCard
44-
headText="Transfer incomplete"
45-
statusMessage="Your transaction has not been sent."
50+
headText={`${actionWord} incomplete`}
51+
statusMessage={`Your transaction has not been sent.`}
4652
icon={<WarningSVG />}
4753
>
48-
<Button
49-
variant="primary"
50-
onClick={() => resetForm()}
51-
label={'Try Again'}
52-
/>
54+
55+
{!isShieldTransaction && (
56+
<Button
57+
variant="primary"
58+
onClick={() => resetForm()}
59+
label={'Try Again'}
60+
/>
61+
)}
5362
</TransactionStatusCard>
5463

5564
default:
5665
return <TransactionStatusCard
57-
headText="Transfer in progres..."
66+
headText={`${actionWord} in progres...`}
5867
statusMessage={pcztTransferStatus}
5968
icon={<Loader />}
6069
/>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from "./TransferConfirm";
2+
export * from "./TransferInput";
3+
export * from "./TransferResult";

packages/web-wallet/src/hooks/usePCZT.ts

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ interface IUsePczt {
1212
toAddress: string,
1313
value: string,
1414
) => void;
15+
handlePcztShieldTransaction: (
16+
accountId: number,
17+
toAddress: string,
18+
value: string,
19+
) => void;
1520
pcztTransferStatus: PcztTransferStatus;
1621
}
1722

@@ -38,10 +43,15 @@ export const usePczt = (): IUsePczt => {
3843
const createPCZT = async (
3944
accountId: number,
4045
toAddress: string,
41-
value: bigint,
46+
value: string,
4247
) => {
4348
try {
44-
return await state.webWallet!.pczt_create(accountId, toAddress, value);
49+
const valueinZats = zecToZats(value);
50+
return await state.webWallet!.pczt_create(
51+
accountId,
52+
toAddress,
53+
valueinZats,
54+
);
4555
} catch (error) {
4656
console.error('Error creating PCZT:', error);
4757
throw error;
@@ -90,48 +100,42 @@ export const usePczt = (): IUsePczt => {
90100
}
91101
};
92102

93-
const handlePcztTransaction = async (
103+
const handlePcztGenericTransaction = async (
94104
accountId: number,
95105
toAddress: string,
96106
value: string,
107+
createPcztFunc: (
108+
accountId: number,
109+
toAddress: string,
110+
value: string,
111+
) => Promise<Pczt>,
97112
) => {
98113
if (!state.webWallet) return;
99114
try {
100115
const chainHeight = await state.webWallet.get_latest_block();
101-
102116
const isSynced =
103117
chainHeight.toString() ===
104118
state.summary?.fully_scanned_height.toString();
105-
106119
setPcztTransferStatus(PcztTransferStatus.CHECK_LATEST_BLOCK);
107120
if (!isSynced) {
108121
setPcztTransferStatus(PcztTransferStatus.SYNCING_CHAIN);
109122
await triggerRescan();
110123
}
111124

112-
//Creating PCZT
113125
setPcztTransferStatus(PcztTransferStatus.CREATING_PCZT);
114-
const valueinZats = zecToZats(value);
115-
const pczt = await createPCZT(accountId, toAddress, valueinZats);
126+
const pczt = await createPcztFunc(accountId, toAddress, value);
116127

117-
//Signing PCZT
118128
setPcztTransferStatus(PcztTransferStatus.SIGNING_PCZT);
119129
const pcztHexStringSigned = await signPczt(pczt, {
120130
recipient: toAddress,
121131
amount: value,
122132
});
123-
124133
const pcztBufferSigned = Buffer.from(pcztHexStringSigned, 'hex');
134+
const signedPczt = Pczt.from_bytes(new Uint8Array(pcztBufferSigned));
125135

126-
const pcztUint8ArraySigned = new Uint8Array(pcztBufferSigned);
127-
128-
const signedPczt = Pczt.from_bytes(pcztUint8ArraySigned);
129-
130-
//Proving PCZT
131136
setPcztTransferStatus(PcztTransferStatus.PROVING_PCZT);
132137
const provedPczt = await provePczt(signedPczt);
133138

134-
//Sending PCZT
135139
setPcztTransferStatus(PcztTransferStatus.SENDING_PCZT);
136140
await sendPczt(provedPczt);
137141
setPcztTransferStatus(PcztTransferStatus.SEND_SUCCESSFUL);
@@ -143,5 +147,30 @@ export const usePczt = (): IUsePczt => {
143147
}
144148
};
145149

146-
return { handlePcztTransaction, pcztTransferStatus };
150+
const handlePcztShieldTransaction = async (
151+
accountId: number,
152+
toAddress: string,
153+
value: string,
154+
) => {
155+
await handlePcztGenericTransaction(
156+
accountId,
157+
toAddress,
158+
value,
159+
async (accountId) => await state.webWallet!.pczt_shield(accountId),
160+
);
161+
};
162+
163+
const handlePcztTransaction = async (
164+
accountId: number,
165+
toAddress: string,
166+
value: string,
167+
) => {
168+
await handlePcztGenericTransaction(accountId, toAddress, value, createPCZT);
169+
};
170+
171+
return {
172+
handlePcztTransaction,
173+
handlePcztShieldTransaction,
174+
pcztTransferStatus,
175+
};
147176
};
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { ZcashYellowPNG } from '../../assets';
3+
import PageHeading from '../../components/PageHeading/PageHeading';
4+
import useBalance from '../../hooks/useBalance';
5+
import { zatsToZec } from '../../utils';
6+
import Button from 'src/components/Button/Button';
7+
import { useWebZjsActions } from 'src/hooks';
8+
import { usePczt } from 'src/hooks/usePCZT';
9+
import { TransferResult } from 'src/components/TransferCards/TransferResult';
10+
11+
export enum ShieldStatus {
12+
DEFAULT = 'default',
13+
SHIELDING = 'shielding',
14+
}
15+
16+
export function ShieldBalance(): React.JSX.Element {
17+
const { unshieldedBalance } = useBalance();
18+
const [addresses, setAddresses] = useState<{
19+
unifiedAddress: string;
20+
transparentAddress: string;
21+
}>({
22+
unifiedAddress: '',
23+
transparentAddress: '',
24+
});
25+
26+
const { getAccountData } = useWebZjsActions();
27+
const { handlePcztShieldTransaction, pcztTransferStatus } = usePczt();
28+
const [shieldStatus, setShieldStatus] = useState(ShieldStatus.DEFAULT);
29+
30+
useEffect(() => {
31+
const fetchData = async () => {
32+
const data = await getAccountData();
33+
if (data)
34+
setAddresses({
35+
unifiedAddress: data.unifiedAddress,
36+
transparentAddress: data.transparentAddress,
37+
});
38+
};
39+
fetchData();
40+
}, [getAccountData]);
41+
42+
43+
const handleShieldBalance = () => {
44+
setShieldStatus(ShieldStatus.SHIELDING);
45+
handlePcztShieldTransaction(1, addresses.unifiedAddress, unshieldedBalance.toString());
46+
}
47+
48+
return (
49+
<div className="flex flex-col w-full">
50+
<PageHeading title="Shield Balance">
51+
<div className="flex items-center gap-2.5">
52+
<span className="text-black text-base font-normal font-inter leading-tight">
53+
Available unshielded balance:
54+
</span>
55+
<div className="px-4 py-2 bg-[#e8e8e8] rounded-3xl flex items-center gap-2.5">
56+
<img
57+
src={ZcashYellowPNG}
58+
alt="Zcash Yellow"
59+
className="w-5 h-5"
60+
/>
61+
<span className="text-[#434343] text-base font-semibold font-inter leading-tight">
62+
{zatsToZec(unshieldedBalance)} ZEC
63+
</span>
64+
</div>
65+
</div>
66+
</PageHeading>
67+
{shieldStatus === ShieldStatus.DEFAULT && (
68+
<div className="min-h-[460px] px-12 py-6 bg-white rounded-3xl border border-[#afafaf] flex-col justify-start items-center gap-6 inline-flex">
69+
<div className="self-stretch h-[413px] flex-col justify-center items-center gap-3 flex">
70+
<div className="self-stretch justify-start items-center gap-2 inline-flex">
71+
<div className="grow shrink basis-0 text-black text-base font-medium font-['Roboto'] leading-normal">
72+
To:
73+
</div>
74+
<div className="p-3 rounded-xl justify-start items-center gap-2 flex">
75+
<div className="text-[#4f4f4f] text-base font-normal font-['Roboto'] break-all leading-normal">
76+
{addresses.unifiedAddress}
77+
</div>
78+
</div>
79+
</div>
80+
<div className="self-stretch justify-start items-center gap-2 inline-flex">
81+
<div className="grow shrink basis-0 text-black text-base font-normal font-['Roboto'] leading-normal">
82+
Amount:
83+
</div>
84+
<div className="px-4 py-1.5 bg-[#e8e8e8] rounded-3xl justify-center items-center gap-2.5 flex">
85+
<div className="text-[#0e0e0e] text-sm font-medium font-['Roboto'] leading-[21px]">
86+
{zatsToZec(unshieldedBalance)} ZEC
87+
</div>
88+
</div>
89+
</div>
90+
<div className="self-stretch pt-6 flex-col justify-center items-center gap-3 flex">
91+
<div className="justify-start items-start inline-flex">
92+
<Button
93+
onClick={handleShieldBalance}
94+
label={'Shield balance'}
95+
/>
96+
</div>
97+
</div>
98+
</div>
99+
</div>
100+
)}
101+
{shieldStatus === ShieldStatus.SHIELDING && (
102+
<TransferResult
103+
pcztTransferStatus={pcztTransferStatus}
104+
resetForm={() => { }}
105+
isShieldTransaction={true}
106+
/>
107+
)}
108+
109+
</div>
110+
);
111+
}
112+

0 commit comments

Comments
 (0)