Skip to content

Commit

Permalink
rewrite state model of webwallet
Browse files Browse the repository at this point in the history
  • Loading branch information
willemolding committed Sep 26, 2024
1 parent f406298 commit 518574d
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 102 deletions.
4 changes: 2 additions & 2 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ rustflags = ["-C", "target-feature=+atomics,+bulk-memory,+mutable-globals"]
# [unstable]
# build-std = ["panic_abort", "std"]

# [build]
# target = "wasm32-unknown-unknown"
[build]
target = "wasm32-unknown-unknown"
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"rust-analyzer.workspace.discoverConfig": null,
"rust-analyzer.cargo.features": "all"
}
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
tracing = "0.1.40"
rayon = { version = "1.8", features = ["web_spin_lock"] }
subtle = "2.6.1"
wasm_thread = { git = "https://github.com/WilsonGramer/wasm_thread.git", rev = "eb41bcc0d98ce0620a313687c0344341391b9d78", features = ["keep_worker_alive"] }
wasm_thread = { git = "https://github.com/WilsonGramer/wasm_thread.git", rev = "eb41bcc0d98ce0620a313687c0344341391b9d78", default-features = false, features = ["keep_worker_alive"] }

wasm_sync = "0.1.2"
http = { version = "1.1.0", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default:
just --list

build:
wasm-pack build --no-opt --target web --scope webzjs --release --out-dir ./packages/webz-core --no-default-features --features="wasm,sync2" -Z build-std="panic_abort,std"
wasm-pack build --target web --scope webzjs --release --out-dir ./packages/webz-core --no-default-features --features="wasm-parallel,sync2" -Z build-std="panic_abort,std"

# All Wasm Tests
test-web *features:
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"scripts": {
"preinstall": "npx only-allow pnpm",
"start:dev": "parcel --no-autoinstall packages/demo-wallet"
"start:dev": "parcel --no-autoinstall packages/demo-wallet",
"build": "parcel build --no-cache --no-autoinstall packages/demo-wallet"
},
"dependencies": {
"@webzjs/webz-core": "workspace:^",
Expand Down
41 changes: 41 additions & 0 deletions packages/demo-wallet/src/App/Actions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import initWasm, { initThreadPool, WebWallet } from "@webzjs/webz-core";

import { Action } from "./App";
import { MAINNET_LIGHTWALLETD_PROXY } from "./constants";

export async function init(dispatch: React.Dispatch<Action>) {
await initWasm();
await initThreadPool(10);
dispatch({
type: "set-web-wallet",
payload: new WebWallet("main", MAINNET_LIGHTWALLETD_PROXY, 1),
});
}

export async function syncStateWithWallet(
webWallet: WebWallet | undefined,
dispatch: React.Dispatch<Action>
) {
if (!webWallet) {
return;
}
let summary = await webWallet?.get_wallet_summary();
if (summary) {
dispatch({ type: "set-summary", payload: summary });
}
let chainHeight = await webWallet?.get_latest_block();
if (chainHeight) {
dispatch({ type: "set-chain-height", payload: chainHeight });
}
}

export async function triggerRescan(
webWallet: WebWallet | undefined,
dispatch: React.Dispatch<Action>
) {
if (!webWallet) {
return;
}
await webWallet?.sync2();
await syncStateWithWallet(webWallet, dispatch);
}
95 changes: 52 additions & 43 deletions packages/demo-wallet/src/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,90 +1,99 @@
import "./App.css";

import React, { useState, useEffect, createContext } from "react";
import React, { useState, useEffect, createContext, useReducer } from "react";

import Tab from "react-bootstrap/Tab";
import Tabs from "react-bootstrap/Tabs";
import Stack from "react-bootstrap/Stack";

import initWasm, {
initThreadPool,
start,
import {
WebWallet,
WalletSummary,
} from "@webzjs/webz-core";

import { init } from "./Actions";
import { Header } from "./components/Header";
import { ImportAccount } from "./components/ImportAccount";
import { SendFunds } from "./components/SendFunds";
import { ReceiveFunds } from "./components/ReceiveFunds";
import { Summary } from "./components/Summary";

const MAINNET_LIGHTWALLETD_PROXY = "https://zcash-mainnet.chainsafe.dev";
type State = {
webWallet?: WebWallet;
activeAccount?: number;
summary?: WalletSummary;
chainHeight?: bigint;
};

export const WalletContext = createContext<WebWallet | null>(null);
const initialState: State = {
activeAccount: undefined,
summary: undefined,
chainHeight: undefined,
};

export function App() {
useEffect(() => {
async function init() {
await initWasm();
await initThreadPool(10);
setWebWallet(new WebWallet("main", MAINNET_LIGHTWALLETD_PROXY, 1));
}
init();
}, []);
export type Action =
| { type: "set-active-account"; payload: number }
| { type: "set-web-wallet"; payload: WebWallet }
| { type: "set-summary"; payload: WalletSummary }
| { type: "set-chain-height"; payload: bigint };

let [webWallet, setWebWallet] = useState<WebWallet | null>(null);
let [summary, setSummary] = useState<WalletSummary | null>(null);
let [chainHeight, setChainHeight] = useState<bigint | null>(null);
let [activeAccoumt, setActiveAccount] = useState<number>(0);

const refreshSummary = async () => {
if (!webWallet) {
return;
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case "set-active-account": {
return { ...state, activeAccount: action.payload };
}
let summary = await webWallet?.get_wallet_summary();
if (summary) {
setSummary(summary);
case "set-web-wallet": {
return { ...state, webWallet: action.payload };
}
let chainHeight = await webWallet?.get_latest_block();
if (chainHeight) {
setChainHeight(chainHeight);
case "set-summary": {
return { ...state, summary: action.payload };
}
};
case "set-chain-height": {
return { ...state, chainHeight: action.payload };
}
default:
return state;
}
};

export const WalletContext = createContext<{
state: State;
dispatch: React.Dispatch<Action>;
}>({ state: initialState, dispatch: () => {} });

export function App() {
const [state, dispatch] = useReducer(reducer, initialState);

useEffect(() => {
init(dispatch);
}, [dispatch]);

const triggerRescan = () => {
if (!webWallet) {
if (!state.webWallet) {
return;
}
console.log("rescanning");
webWallet.sync2().then(() => {
state.webWallet.sync2().then(() => {
console.log("rescan complete");
});
};

return (
<div>
<WalletContext.Provider value={webWallet}>
<WalletContext.Provider value={{ state, dispatch }}>
<Stack>
<h1>WebZjs Wallet Demo</h1>
<Header
walletSummary={summary}
refreshSummary={refreshSummary}
activeAccount={activeAccoumt}
setActiveAccount={setActiveAccount}
triggerRescan={triggerRescan}
chainHeight={chainHeight}
/>
<Header />
<Tabs
defaultActiveKey="import"
id="base-wallet-tabs"
className="mb-3"
>
<Tab eventKey="import" title="Import Account">
<ImportAccount refreshSummary={refreshSummary} />
<ImportAccount />
</Tab>
<Tab eventKey="summary" title="Summary">
<Summary walletSummary={summary} />
<Summary summary={state.summary}/>
</Tab>
<Tab eventKey="send" title="Send">
<SendFunds />
Expand Down
1 change: 1 addition & 0 deletions packages/demo-wallet/src/App/Constants.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const MAINNET_LIGHTWALLETD_PROXY = "https://zcash-mainnet.chainsafe.dev";
37 changes: 13 additions & 24 deletions packages/demo-wallet/src/App/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
import React, { useContext, useEffect, useState } from "react";
import React, { useContext } from "react";

import Form from "react-bootstrap/Form";
import Card from "react-bootstrap/Card";
import Stack from "react-bootstrap/Stack";

import { WalletContext } from "../App";
import { WalletSummary } from "@webzjs/webz-core";
import { syncStateWithWallet, triggerRescan } from "../Actions";
import { Button } from "react-bootstrap";

export function Header({
walletSummary,
refreshSummary,
activeAccount,
setActiveAccount,
triggerRescan,
chainHeight,
}: {
walletSummary: WalletSummary | null;
refreshSummary: () => Promise<void>;
activeAccount: number;
setActiveAccount: (account: number) => void;
triggerRescan: () => void;
chainHeight: bigint | null;
}) {
export function Header() {

const { state, dispatch } = useContext(WalletContext);

return (
<Stack direction="horizontal" gap={3}>
<Form.Select
value={activeAccount}
onChange={(e) => setActiveAccount(parseInt(e.target.value))}
value={state.activeAccount}
onChange={(e) => dispatch({ type: "set-active-account", payload: parseInt(e.target.value)})}
>
{walletSummary?.account_balances.map(([id]) => (
{state.summary?.account_balances.map(([id]) => (
<option key={id} value={id}>
Account {id}
</option>
Expand All @@ -40,12 +29,12 @@ export function Header({
<Card.Text>Available Balance: {0} ZEC</Card.Text>
</Card>
<Card style={{ width: "30rem" }}>
<Card.Text>Chain Height: {chainHeight ? ""+chainHeight : '?'}</Card.Text>
<Card.Text>Synced Height: {walletSummary?.fully_scanned_height ? walletSummary?.fully_scanned_height : '?'}</Card.Text>
<Card.Text>Chain Height: {state.chainHeight ? ""+state.chainHeight : '?'}</Card.Text>
<Card.Text>Synced Height: {state.summary?.fully_scanned_height ? state.summary?.fully_scanned_height : '?'}</Card.Text>
</Card>
<Stack>
<Button onClick={async () => await refreshSummary()}>Refresh</Button>
<Button onClick={() => triggerRescan()}>Sync</Button>
<Button onClick={async () => await syncStateWithWallet(state.webWallet, dispatch)}>Refresh</Button>
<Button onClick={() => triggerRescan(state.webWallet, dispatch)}>Sync</Button>
</Stack>
</Stack>
);
Expand Down
9 changes: 5 additions & 4 deletions packages/demo-wallet/src/App/components/ImportAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,21 @@ import Form from "react-bootstrap/Form";
import { ToastContainer, toast } from "react-toastify";

import { WalletContext } from "../App";
import { syncStateWithWallet } from "../Actions";

export function ImportAccount({refreshSummary}: {refreshSummary: () => Promise<void>}) {
let webWallet = useContext(WalletContext);
export function ImportAccount() {
let {state, dispatch} = useContext(WalletContext);

let [birthdayHeight, setBirthdayHeight] = useState(2657762);
let [seedPhrase, setSeedPhrase] = useState("mix sample clay sweet planet lava giraffe hand fashion switch away pool rookie earth purity truly square trumpet goose move actor save jaguar volume");

const handleSubmit = async (event: FormEvent) => {
event.preventDefault();
await webWallet?.create_account(seedPhrase, 0, birthdayHeight);
await state.webWallet?.create_account(seedPhrase, 0, birthdayHeight);
toast.success("Account imported successfully", {
position: "top-center",
});
await refreshSummary();
await syncStateWithWallet(state.webWallet, dispatch);
setBirthdayHeight(0);
setSeedPhrase("");
};
Expand Down
4 changes: 0 additions & 4 deletions packages/demo-wallet/src/App/components/ReceiveFunds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ import Form from "react-bootstrap/Form";
export function ReceiveFunds() {
return (
<Form>
<Form.Label>To Account:</Form.Label>
<Form.Select>
<option>Account 1</option>
</Form.Select>
<Form.Text className="text-muted">
Share one of these addresses to receive funds
</Form.Text>
Expand Down
15 changes: 5 additions & 10 deletions packages/demo-wallet/src/App/components/Summary.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import React, { useContext, useEffect, useState } from "react";

import Form from "react-bootstrap/Form";

import { WalletContext } from "../App";
import { WalletSummary, AccountBalance } from "@webzjs/webz-core";
import { Button } from "react-bootstrap";
import React from "react";
import { WalletSummary } from "@webzjs/webz-core";

export function Summary({
walletSummary,
summary,
}: {
walletSummary: WalletSummary | null;
summary: WalletSummary | undefined;
}) {
return (
<div>
<pre>
{JSON.stringify(
walletSummary?.toJSON(),
summary?.toJSON(),
(key, value) =>
typeof value === "bigint" ? value.toString() : value,
2
Expand Down
Loading

0 comments on commit 518574d

Please sign in to comment.