Skip to content

Commit

Permalink
add account summary balances
Browse files Browse the repository at this point in the history
  • Loading branch information
Lykhoyda committed Dec 12, 2024
1 parent 3631610 commit 8bdd7ba
Show file tree
Hide file tree
Showing 14 changed files with 231 additions and 61 deletions.
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
[workspace]
resolver = "2"

members = [ "crates/webz-common",
"crates/webz-keys", "crates/webz-requests",
members = [
"crates/webz-common",
"crates/webz-keys",
"crates/webz-requests",
"crates/webz-wallet",
]

Expand Down
2 changes: 0 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ build-keys *features:
build-requests *features:
cd crates/webz-requests && wasm-pack build -t web --release --scope webzjs --out-dir ../../packages/webz-requests --no-default-features --features="{{features}}" -Z build-std="panic_abort,std"


# All Wasm Tests
test-web *features:
WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --firefox --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std"
Expand All @@ -28,7 +27,6 @@ test-message-board-web *features:
test-simple-web *features:
WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --chrome --no-default-features --features "wasm no-bundler {{features}}" -Z build-std="panic_abort,std" --test simple-sync-and-send


# simple example: additional args:, sqlite-db
example-simple *features:
RUST_LOG="info,zcash_client_backend::sync=debug" cargo run -r --example simple-sync --features "native {{features}}"
Expand Down
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/MetaMask/template-snap-monorepo.git"
},
"source": {
"shasum": "5kG/5tKuPrrpApOlFvFR5gCuTloSUZfJ4QCjtVezHu8=",
"shasum": "trfvzpmDcGt2TqfetqwfKPa8kHXQKGf4cytN7W+dHZU=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/web-wallet/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useInterval } from 'usehooks-ts';
import { RESCAN_INTERVAL } from '@webzjs/demo-wallet/src/App/Constants.tsx';
import { useWebZjsActions } from '@hooks/useWebzjsActions.ts';
import Layout from '@components/Layout/Layout.tsx';
import { Outlet } from 'react-router-dom';
import { RESCAN_INTERVAL } from './config/constants.ts';

function App() {
const { triggerRescan } = useWebZjsActions();
Expand Down
3 changes: 3 additions & 0 deletions packages/web-wallet/src/assets/icons/coins.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/web-wallet/src/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import ClockSvg from './icons/clock.svg';
import ShieldSvg from './icons/shield.svg';
import ShieldDividedSvg from './icons/shield-divided.svg';
import SummarySvg from './icons/summary.svg';
import CoinsSvg from './icons/coins.svg';

export {
ChainsafeSvg,
Expand All @@ -26,4 +27,5 @@ export {
ShieldSvg,
ShieldDividedSvg,
SummarySvg,
CoinsSvg,
};
4 changes: 2 additions & 2 deletions packages/web-wallet/src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import Footer from '../Footer/Footer.tsx';

const Layout = (): React.JSX.Element => {
return (
<div className="flex flex-col min-h-screen">
<div className="container mx-auto flex flex-col min-h-screen">
<Header />
<main className="flex-grow flex justify-center py-3">
<main className="flex-grow flex justify-center py-3 self-stretch w-full">
<Outlet />
</main>
<Footer />
Expand Down
43 changes: 15 additions & 28 deletions packages/web-wallet/src/context/WebzjsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,44 @@
import React, { createContext, useReducer, useEffect } from 'react';
import type { ReactNode } from 'react';
import type { MetaMaskInpageProvider } from '@metamask/providers';
import { get, set } from 'idb-keyval';

import initWebzWallet, { initThreadPool, WebWallet } from '@webzjs/webz-wallet';
import initWebzWallet, {
initThreadPool,
WalletSummary,
WebWallet,
} from '@webzjs/webz-wallet';
import initWebzKeys from '@webzjs/webz-keys';

import type { Snap } from '../types';
import { getSnapsProvider } from '../utils';
import { MAINNET_LIGHTWALLETD_PROXY } from '../config/constants.ts';

interface Summary {
chain_tip_height: number;
fully_scanned_height: number;
next_sapling_subtree_index: bigint;
next_orchard_subtree_index: bigint;
account_balances: [number, number][];
}

interface State {
webWallet: WebWallet | null;
provider: MetaMaskInpageProvider | null;
installedSnap: Snap | null;
error: Error | null;
summary: Summary | null;
chainHeight: bigint | null;
activeAccount: number | null;
summary?: WalletSummary;
chainHeight?: bigint;
activeAccount?: number;
syncInProgress: boolean;
loading: boolean;
}

type Action =
| { type: 'set-web-wallet'; payload: WebWallet }
| { type: 'set-provider'; payload: MetaMaskInpageProvider | null }
| { type: 'set-error'; payload: Error | null }
| { type: 'set-summary'; payload: Summary }
| { type: 'set-summary'; payload: WalletSummary }
| { type: 'set-chain-height'; payload: bigint }
| { type: 'set-active-account'; payload: number }
| { type: 'set-sync-in-progress'; payload: boolean }
| { type: 'set-loading'; payload: boolean };

const initialState: State = {
webWallet: null,
provider: null,
installedSnap: null,
error: null,
summary: null,
chainHeight: null,
activeAccount: null,
summary: undefined,
chainHeight: undefined,
activeAccount: undefined,
syncInProgress: false,
loading: true,
};
Expand All @@ -56,8 +47,6 @@ function reducer(state: State, action: Action): State {
switch (action.type) {
case 'set-web-wallet':
return { ...state, webWallet: action.payload };
case 'set-provider':
return { ...state, provider: action.payload };
case 'set-error':
return { ...state, error: action.payload };
case 'set-summary':
Expand Down Expand Up @@ -102,10 +91,8 @@ export const WebZjsProvider = ({ children }: { children: ReactNode }) => {
await initThreadPool(10);
} catch (err) {
console.error(err);
throw Error('Unable to initialize Thread Pool');
return Error('Unable to initialize Thread Pool');
}
const provider = await getSnapsProvider();
dispatch({ type: 'set-provider', payload: provider });

const bytes = await get('wallet');
let wallet;
Expand Down Expand Up @@ -138,9 +125,9 @@ export const WebZjsProvider = ({ children }: { children: ReactNode }) => {
}

dispatch({ type: 'set-loading', payload: false });
} catch (err: never) {
} catch (err) {
console.error('Initialization error:', err);
dispatch({ type: 'set-error', payload: err.toString() });
dispatch({ type: 'set-error', payload: Error(String(err)) });
dispatch({ type: 'set-loading', payload: false });
}
}
Expand Down
112 changes: 92 additions & 20 deletions packages/web-wallet/src/hooks/useWebzjsActions.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,85 @@
import { set } from 'idb-keyval';
import { useCallback } from 'react';
import { useWebZjsContext } from '../context/WebzjsContext.tsx';

export function useWebZjsActions() {
export interface AccountBalance {
totalShieldedBalance: number;
unshieldedBalance: number;
totalBalance: number;
}

interface UseWebzjsActions {
addNewAccountFromUfvk: (
ufvk: string,
birthdayHeight: number,
) => Promise<void>;
getBalance: () => AccountBalance;
triggerRescan: () => Promise<void>;
flushDbToStore: () => Promise<void>;
syncStateWithWallet: () => Promise<void>;
}

export function useWebZjsActions(): UseWebzjsActions {
const { state, dispatch } = useWebZjsContext();
console.log('state', state);

async function syncStateWithWallet() {
const syncStateWithWallet = useCallback(async () => {
if (!state.webWallet) {
dispatch({
type: 'set-error',
payload: new Error('Wallet not initialized'),
});
return;
}
const summary = await state.webWallet.get_wallet_summary();
if (summary) {
dispatch({ type: 'set-summary', payload: summary });
}
const chainHeight = await state.webWallet.get_latest_block();
if (chainHeight) {
dispatch({ type: 'set-chain-height', payload: chainHeight });
try {
const summary = await state.webWallet.get_wallet_summary();
if (summary) {
dispatch({ type: 'set-summary', payload: summary });
}
const chainHeight = await state.webWallet.get_latest_block();
if (chainHeight) {
dispatch({ type: 'set-chain-height', payload: chainHeight });
}
} catch (error) {
console.error('Error syncing state with wallet:', error);
dispatch({ type: 'set-error', payload: error });
}
}
}, [state.webWallet, dispatch]);

const addNewAccountFromUfvk = useCallback(
async (ufvk: string, birthdayHeight: number) => {
const account_id =
(await state.webWallet?.create_account_ufvk(ufvk, birthdayHeight)) || 0;
dispatch({ type: 'set-active-account', payload: account_id });

if (state.webWallet) {
const summary = await state.webWallet.get_wallet_summary();
console.log(summary?.account_balances.length);
}
await syncStateWithWallet();
},
[dispatch, state.webWallet, syncStateWithWallet],
);

async function flushDbToStore() {
const flushDbToStore = useCallback(async () => {
if (!state.webWallet) {
dispatch({
type: 'set-error',
payload: new Error('Wallet not initialized'),
});
return;
}
console.info('Serializing wallet and dumping to IndexedDB store');
const bytes = await state.webWallet.db_to_bytes();
await set('wallet', bytes);
console.info('Wallet saved to storage');
}
try {
console.info('Serializing wallet and dumping to IndexedDB store');
const bytes = await state.webWallet.db_to_bytes();
await set('wallet', bytes);
console.info('Wallet saved to storage');
} catch (error) {
console.error('Error flushing DB to store:', error);
dispatch({ type: 'set-error', payload: error });
}
}, [state.webWallet, dispatch]);

async function triggerRescan() {
const triggerRescan = useCallback(async () => {
if (state.loading) {
dispatch({ type: 'set-error', payload: new Error('App not yet loaded') });
return;
Expand All @@ -49,7 +91,7 @@ export function useWebZjsActions() {
});
return;
}
if (state.activeAccount == undefined) {
if (state.activeAccount === undefined) {
dispatch({ type: 'set-error', payload: new Error('No active account') });
return;
}
Expand All @@ -73,10 +115,40 @@ export function useWebZjsActions() {
} finally {
dispatch({ type: 'set-sync-in-progress', payload: false });
}
}
}, [
state.loading,
state.webWallet,
state.activeAccount,
state.syncInProgress,
dispatch,
syncStateWithWallet,
flushDbToStore,
]);

const getBalance = useCallback((): AccountBalance => {
const activeBalanceReport = state.summary?.account_balances.find(
([id]) => id === state.activeAccount,
);

const totalShieldedBalance = activeBalanceReport
? activeBalanceReport[1].sapling_balance +
activeBalanceReport[1].orchard_balance
: 0;

const unshieldedBalance = activeBalanceReport?.[1]?.unshielded_balance || 0;

return {
totalShieldedBalance,
unshieldedBalance,
totalBalance: totalShieldedBalance + unshieldedBalance,
};
}, [state.activeAccount, state.summary?.account_balances]);

return {
getBalance,
addNewAccountFromUfvk,
triggerRescan,
flushDbToStore,
syncStateWithWallet,
};
}
Loading

0 comments on commit 8bdd7ba

Please sign in to comment.