Skip to content

Commit f406298

Browse files
committed
add ability to fetch chain tip by forwarding lightwalletd calls
1 parent aff28fc commit f406298

File tree

6 files changed

+146
-112
lines changed

6 files changed

+146
-112
lines changed

packages/demo-wallet/src/App/App.tsx

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,24 @@ import Tab from "react-bootstrap/Tab";
66
import Tabs from "react-bootstrap/Tabs";
77
import Stack from "react-bootstrap/Stack";
88

9-
10-
import initWasm, { initThreadPool, start, WebWallet } from "@webzjs/webz-core";
9+
import initWasm, {
10+
initThreadPool,
11+
start,
12+
WebWallet,
13+
WalletSummary,
14+
} from "@webzjs/webz-core";
1115

1216
import { Header } from "./components/Header";
1317
import { ImportAccount } from "./components/ImportAccount";
1418
import { SendFunds } from "./components/SendFunds";
1519
import { ReceiveFunds } from "./components/ReceiveFunds";
16-
import { Balance } from "./components/Balance";
17-
18-
19-
const SAPLING_ACTIVATION = 419200;
20-
const ORCHARD_ACTIVATION = 1687104;
21-
const TIP = 2442739;
20+
import { Summary } from "./components/Summary";
2221

2322
const MAINNET_LIGHTWALLETD_PROXY = "https://zcash-mainnet.chainsafe.dev";
24-
const TESTNET_LIGHTWALLETD_PROXY = "https://zcash-testnet.chainsafe.dev";
2523

2624
export const WalletContext = createContext<WebWallet | null>(null);
2725

2826
export function App() {
29-
3027
useEffect(() => {
3128
async function init() {
3229
await initWasm();
@@ -37,27 +34,65 @@ export function App() {
3734
}, []);
3835

3936
let [webWallet, setWebWallet] = useState<WebWallet | null>(null);
37+
let [summary, setSummary] = useState<WalletSummary | null>(null);
38+
let [chainHeight, setChainHeight] = useState<bigint | null>(null);
39+
let [activeAccoumt, setActiveAccount] = useState<number>(0);
40+
41+
const refreshSummary = async () => {
42+
if (!webWallet) {
43+
return;
44+
}
45+
let summary = await webWallet?.get_wallet_summary();
46+
if (summary) {
47+
setSummary(summary);
48+
}
49+
let chainHeight = await webWallet?.get_latest_block();
50+
if (chainHeight) {
51+
setChainHeight(chainHeight);
52+
}
53+
};
54+
55+
const triggerRescan = () => {
56+
if (!webWallet) {
57+
return;
58+
}
59+
console.log("rescanning");
60+
webWallet.sync2().then(() => {
61+
console.log("rescan complete");
62+
});
63+
};
4064

4165
return (
4266
<div>
4367
<WalletContext.Provider value={webWallet}>
4468
<Stack>
45-
<h1>WebZjs Wallet Demo</h1>
46-
<Header />
47-
<Tabs defaultActiveKey="import" id="base-wallet-tabs" className="mb-3">
48-
<Tab eventKey="import" title="Import Account">
49-
<ImportAccount />
50-
</Tab>
51-
<Tab eventKey="balance" title="Balance">
52-
<Balance />
53-
</Tab>
54-
<Tab eventKey="send" title="Send">
55-
<SendFunds />
56-
</Tab>
57-
<Tab eventKey="receive" title="Receive">
58-
<ReceiveFunds />
59-
</Tab>
60-
</Tabs>
69+
<h1>WebZjs Wallet Demo</h1>
70+
<Header
71+
walletSummary={summary}
72+
refreshSummary={refreshSummary}
73+
activeAccount={activeAccoumt}
74+
setActiveAccount={setActiveAccount}
75+
triggerRescan={triggerRescan}
76+
chainHeight={chainHeight}
77+
/>
78+
<Tabs
79+
defaultActiveKey="import"
80+
id="base-wallet-tabs"
81+
className="mb-3"
82+
>
83+
<Tab eventKey="import" title="Import Account">
84+
<ImportAccount refreshSummary={refreshSummary} />
85+
</Tab>
86+
<Tab eventKey="summary" title="Summary">
87+
<Summary walletSummary={summary} />
88+
</Tab>
89+
<Tab eventKey="send" title="Send">
90+
<SendFunds />
91+
</Tab>
92+
<Tab eventKey="receive" title="Receive">
93+
<ReceiveFunds />
94+
</Tab>
95+
</Tabs>
6196
</Stack>
6297
</WalletContext.Provider>
6398
</div>

packages/demo-wallet/src/App/components/Balance.tsx

Lines changed: 0 additions & 60 deletions
This file was deleted.
Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,52 @@
11
import React, { useContext, useEffect, useState } from "react";
22

33
import Form from "react-bootstrap/Form";
4+
import Card from "react-bootstrap/Card";
5+
import Stack from "react-bootstrap/Stack";
46

57
import { WalletContext } from "../App";
6-
import { WalletSummary, AccountBalance } from "@webzjs/webz-core";
8+
import { WalletSummary } from "@webzjs/webz-core";
79
import { Button } from "react-bootstrap";
810

9-
export function Header() {
10-
let webWallet = useContext(WalletContext);
11-
let [summary, setSummary] = useState<WalletSummary | null>();
12-
13-
let resyncSummary = async () => {
14-
if (!webWallet) {
15-
return;
16-
}
17-
console.log("fetching balance");
18-
let summary = await webWallet?.get_wallet_summary();
19-
console.log("summary", summary);
20-
console.log("balances");
21-
22-
setSummary(summary);
23-
};
24-
11+
export function Header({
12+
walletSummary,
13+
refreshSummary,
14+
activeAccount,
15+
setActiveAccount,
16+
triggerRescan,
17+
chainHeight,
18+
}: {
19+
walletSummary: WalletSummary | null;
20+
refreshSummary: () => Promise<void>;
21+
activeAccount: number;
22+
setActiveAccount: (account: number) => void;
23+
triggerRescan: () => void;
24+
chainHeight: bigint | null;
25+
}) {
2526
return (
26-
<div className="p-2">
27-
<span className="me-2">Balance: </span>
28-
</div>
27+
<Stack direction="horizontal" gap={3}>
28+
<Form.Select
29+
value={activeAccount}
30+
onChange={(e) => setActiveAccount(parseInt(e.target.value))}
31+
>
32+
{walletSummary?.account_balances.map(([id]) => (
33+
<option key={id} value={id}>
34+
Account {id}
35+
</option>
36+
))}
37+
</Form.Select>
38+
<Card style={{ width: "30rem" }}>
39+
<Card.Title>Balance: {0} ZEC</Card.Title>
40+
<Card.Text>Available Balance: {0} ZEC</Card.Text>
41+
</Card>
42+
<Card style={{ width: "30rem" }}>
43+
<Card.Text>Chain Height: {chainHeight ? ""+chainHeight : '?'}</Card.Text>
44+
<Card.Text>Synced Height: {walletSummary?.fully_scanned_height ? walletSummary?.fully_scanned_height : '?'}</Card.Text>
45+
</Card>
46+
<Stack>
47+
<Button onClick={async () => await refreshSummary()}>Refresh</Button>
48+
<Button onClick={() => triggerRescan()}>Sync</Button>
49+
</Stack>
50+
</Stack>
2951
);
3052
}

packages/demo-wallet/src/App/components/ImportAccount.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ToastContainer, toast } from "react-toastify";
66

77
import { WalletContext } from "../App";
88

9-
export function ImportAccount() {
9+
export function ImportAccount({refreshSummary}: {refreshSummary: () => Promise<void>}) {
1010
let webWallet = useContext(WalletContext);
1111

1212
let [birthdayHeight, setBirthdayHeight] = useState(2657762);
@@ -18,6 +18,7 @@ export function ImportAccount() {
1818
toast.success("Account imported successfully", {
1919
position: "top-center",
2020
});
21+
await refreshSummary();
2122
setBirthdayHeight(0);
2223
setSeedPhrase("");
2324
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { useContext, useEffect, useState } from "react";
2+
3+
import Form from "react-bootstrap/Form";
4+
5+
import { WalletContext } from "../App";
6+
import { WalletSummary, AccountBalance } from "@webzjs/webz-core";
7+
import { Button } from "react-bootstrap";
8+
9+
export function Summary({
10+
walletSummary,
11+
}: {
12+
walletSummary: WalletSummary | null;
13+
}) {
14+
return (
15+
<div>
16+
<pre>
17+
{JSON.stringify(
18+
walletSummary?.toJSON(),
19+
(key, value) =>
20+
typeof value === "bigint" ? value.toString() : value,
21+
2
22+
)}
23+
</pre>
24+
</div>
25+
);
26+
}

src/bindgen/wallet.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::collections::HashMap;
21
use std::num::NonZeroU32;
32

43
use serde::{Deserialize, Serialize};
@@ -10,7 +9,10 @@ use crate::error::Error;
109
use crate::{BlockRange, MemoryWallet, Wallet, PRUNING_DEPTH};
1110
use wasm_thread as thread;
1211
use zcash_address::ZcashAddress;
13-
use zcash_client_backend::proto::service::compact_tx_streamer_client::CompactTxStreamerClient;
12+
use zcash_client_backend::proto::service::{
13+
ChainSpec,
14+
compact_tx_streamer_client::CompactTxStreamerClient
15+
};
1416
use zcash_client_memory::MemoryWalletDb;
1517
use zcash_keys::keys::UnifiedFullViewingKey;
1618
use zcash_primitives::consensus::{self, BlockHeight};
@@ -174,12 +176,21 @@ impl WebWallet {
174176
.transfer(seed_phrase, from_account_index, to_address, value)
175177
.await
176178
}
179+
180+
/// Forwards a call to lightwalletd to retrieve the height of the latest block in the chain
181+
pub async fn get_latest_block(
182+
&self,
183+
) -> Result<u64, Error> {
184+
self.client().get_latest_block(ChainSpec{}).await.map(|response| {
185+
response.into_inner().height
186+
}).map_err(Error::from)
187+
}
177188
}
178189

179-
#[wasm_bindgen]
180190
#[derive(Debug, Serialize, Deserialize)]
191+
#[wasm_bindgen(inspectable)]
181192
pub struct WalletSummary {
182-
account_balances: HashMap<u32, AccountBalance>,
193+
account_balances: Vec<(u32, AccountBalance)>,
183194
pub chain_tip_height: u32,
184195
pub fully_scanned_height: u32,
185196
// scan_progress: Option<Ratio<u64>>,
@@ -195,7 +206,6 @@ impl WalletSummary {
195206
}
196207
}
197208

198-
199209
#[derive(Debug, Serialize, Deserialize)]
200210
pub struct AccountBalance {
201211
pub sapling_balance: u64,

0 commit comments

Comments
 (0)