Skip to content

Commit

Permalink
Refactor balances.ts to use protobuf types (#453)
Browse files Browse the repository at this point in the history
* Refactor balances.ts to use protobuf types

* Review updates
  • Loading branch information
grod220 authored Feb 6, 2024
1 parent 046a9a2 commit 12cd517
Show file tree
Hide file tree
Showing 67 changed files with 1,568 additions and 1,251 deletions.
4 changes: 2 additions & 2 deletions apps/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
"@types/chrome": "0.0.260",
"@types/firefox-webext-browser": "^120.0.0",
"@types/node": "^20.11.16",
"@types/react": "^18.2.53",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18",
"autoprefixer": "^10.4.17",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.10.0",
"html-webpack-plugin": "^5.6.0",
"postcss": "^8.4.33",
"postcss": "^8.4.34",
"postcss-loader": "^8.1.0",
"style-loader": "^3.3.4",
"tailwindcss": "^3.4.1",
Expand Down
6 changes: 3 additions & 3 deletions apps/extension/src/routes/popup/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { IndexHeader } from './index-header';
import { useStore } from '../../../state';
import { BlockSync } from './block-sync';
import { localExtStorage, sessionExtStorage } from '@penumbra-zone/storage';
import { accountAddrSelector } from '../../../state/wallets';
import { addrByIndexSelector } from '../../../state/wallets';

export interface PopupLoaderData {
lastBlockSynced: number;
Expand All @@ -32,14 +32,14 @@ export const popupIndexLoader = async (): Promise<Response | PopupLoaderData> =>
};

export const PopupIndex = () => {
const getAccount = useStore(accountAddrSelector);
const getAddrByIndex = useStore(addrByIndexSelector);

return (
<div className='relative flex h-full flex-col items-stretch justify-start bg-left-bottom px-[30px]'>
<div className='absolute bottom-[50px] left-[-10px] -z-10 h-[715px] w-[900px] overflow-hidden bg-logo opacity-10' />
<IndexHeader />
<div className='my-32'>
<SelectAccount getAccount={getAccount} />
<SelectAccount getAddrByIndex={getAddrByIndex} />
</div>
<BlockSync />
</div>
Expand Down
23 changes: 10 additions & 13 deletions apps/extension/src/state/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
} from '@penumbra-zone/wasm-ts';
import { Key } from '@penumbra-zone/crypto-web';
import { ExtensionStorage, LocalStorageState } from '@penumbra-zone/storage';
import { Wallet, WalletCreate, bech32Address } from '@penumbra-zone/types';
import { Wallet, WalletCreate } from '@penumbra-zone/types';
import { Address } from '@buf/penumbra-zone_penumbra.bufbuild_es/penumbra/core/keys/v1alpha1/keys_pb';

export interface WalletsSlice {
all: Wallet[];
Expand Down Expand Up @@ -74,17 +75,13 @@ export const createWalletsSlice =
export const walletsSelector = (state: AllSlices) => state.wallets;
export const getActiveWallet = (state: AllSlices) => state.wallets.all[0];

export const accountAddrSelector = (state: AllSlices) => (index: number, ephemeral: boolean) => {
const active = getActiveWallet(state);
if (!active) return;
export const addrByIndexSelector =
(state: AllSlices) =>
(index: number, ephemeral: boolean): Address => {
const active = getActiveWallet(state);
if (!active) throw new Error('No active wallet');

const addr = ephemeral
? getEphemeralByIndex(active.fullViewingKey, index)
: getAddressByIndex(active.fullViewingKey, index);
const bech32Addr = bech32Address(addr);

return {
address: bech32Addr,
index,
return ephemeral
? getEphemeralByIndex(active.fullViewingKey, index)
: getAddressByIndex(active.fullViewingKey, index);
};
};
6 changes: 4 additions & 2 deletions apps/webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,25 @@
"@radix-ui/react-icons": "^1.3.0",
"@tanstack/react-query": "^5.18.1",
"bignumber.js": "^9.1.2",
"immer": "^10.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet": "^6.1.0",
"react-loader-spinner": "^6.1.6",
"react-router-dom": "^6.22.0",
"tailwindcss": "^3.4.1",
"zod": "^3.22.4",
"zustand": "^4.5.0"
},
"devDependencies": {
"@types/node": "^20.11.16",
"@types/react": "^18.2.53",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.18",
"@types/react-helmet": "^6.1.11",
"@vitejs/plugin-react-swc": "^3.6.0",
"autoprefixer": "^10.4.17",
"firebase-tools": "^13.1.0",
"postcss": "^8.4.33",
"postcss": "^8.4.34",
"vite": "^5.0.12",
"vitest": "^1.2.2"
}
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/src/clients/penumbra-port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ declare global {
export const getPenumbraPort = (serviceTypeName: string) => {
const { port1: port, port2: transferPort } = new MessageChannel();
if (!(penumbra in window)) throw Error('No Penumbra global (extension not installed)');
const initPort = window[penumbra].services?.[serviceTypeName];
const initPort = window[penumbra]?.services?.[serviceTypeName];
if (!initPort) throw Error(`No init port for service ${serviceTypeName}`);
initPort.postMessage(
{
Expand Down
110 changes: 52 additions & 58 deletions apps/webapp/src/components/dashboard/assets-table.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@penumbra-zone/ui';
import { displayUsd, fromBaseUnitAmountAndMetadata } from '@penumbra-zone/types';
import { LoaderFunction, useLoaderData } from 'react-router-dom';
import { throwIfExtNotInstalled } from '../../fetchers/is-connected.ts';
import { AccountBalance, getBalancesByAccount } from '../../fetchers/balances.ts';
import { AssetIcon } from '../shared/asset-icon.tsx';
import { AddressIcon } from '@penumbra-zone/ui/components/ui/address-icon';
import { Address } from '@penumbra-zone/ui/components/ui/address.tsx';
import { AddressComponent } from '@penumbra-zone/ui/components/ui/address-component';
import {
AccountGroupedBalances,
getBalancesByAccount,
} from '../../fetchers/balances/by-account.ts';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@penumbra-zone/ui';
import { AssetIcon } from '../shared/asset-icon.tsx';
import { displayUsd, hasDenomMetadata } from '@penumbra-zone/types';
import { ValueViewComponent } from '@penumbra-zone/ui/components/ui/tx/view/value.tsx';

export const AssetsLoader: LoaderFunction = async (): Promise<AccountBalance[]> => {
export const AssetsLoader: LoaderFunction = async (): Promise<AccountGroupedBalances[]> => {
throwIfExtNotInstalled();
return await getBalancesByAccount();
};

export default function AssetsTable() {
const data = useLoaderData() as AccountBalance[];
const data = useLoaderData() as AccountGroupedBalances[];

if (data.length === 0) {
return (
Expand All @@ -31,73 +35,63 @@ export default function AssetsTable() {

return (
<div className='flex flex-col gap-6'>
{data.map(a => {
return (
<div key={a.index} className='flex flex-col gap-4'>
<div className='flex flex-col items-center justify-center'>
<div className='flex flex-col items-center justify-center gap-2 md:flex-row'>
<div className='flex items-center gap-2'>
<AddressIcon address={a.address} size={20} />
<h2 className='font-bold md:text-base xl:text-xl'>Account #{a.index}</h2>{' '}
</div>

<Address address={a.address} />
{data.map((a, index) => (
<div key={index} className='flex flex-col gap-4'>
<div className='flex flex-col items-center justify-center'>
<div className='flex flex-col items-center justify-center gap-2 md:flex-row'>
<div className='flex items-center gap-2'>
<AddressIcon address={a.address} size={20} />
<h2 className='font-bold md:text-base xl:text-xl'>Account #{a.index.account}</h2>
</div>
<AddressComponent address={a.address} />
</div>
<div className='flex flex-col gap-[34px] md:hidden'>
{a.balances.map((asset, i) => (
<div key={i} className='flex items-center justify-between border-b pb-3'>
<div className='flex items-center gap-2'>
<AssetIcon name={asset.metadata.display} />
<p className='font-mono text-base font-bold'>{asset.metadata.display}</p>
</div>
<p className='font-mono text-base font-bold'>
{fromBaseUnitAmountAndMetadata(asset.amount, asset.metadata).toFormat()}
</p>
<p className='font-mono text-base font-bold'>
{asset.usdcValue == 0 ? '$–' : `$${displayUsd(asset.usdcValue)}`}
</p>
</div>
))}
</div>
<Table className='hidden md:table'>
<TableHeader>
<TableRow>
<TableHead className='w-1/3 text-center'>Asset</TableHead>
<TableHead className='w-1/3 text-center'>Balance</TableHead>
<TableHead className='w-1/3 text-center'>Value</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{a.balances.map((asset, i) => (
<TableRow key={i}>
</div>

<Table className='md:table'>
<TableHeader>
<TableRow>
<TableHead className='w-1/3 text-center'>Asset</TableHead>
<TableHead className='w-1/3 text-center'>Balance</TableHead>
<TableHead className='w-1/3 text-center'>Value</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{a.balances.map((assetBalance, index) => {
return (
<TableRow key={index}>
<TableCell className='w-1/3'>
<div className='flex items-center gap-2'>
<AssetIcon name={asset.metadata.display} />
<p className='font-mono text-base font-bold'>{asset.metadata.display}</p>
{hasDenomMetadata(assetBalance.value) && (
<>
<AssetIcon metadata={assetBalance.value.valueView.value.metadata} />
<p className='font-mono text-base font-bold'>
{assetBalance.value.valueView.value.metadata.display}
</p>
</>
)}
</div>
</TableCell>
<TableCell className='w-1/3 text-center font-mono'>
<div className='flex flex-col'>
<p className='text-base font-bold'>
{fromBaseUnitAmountAndMetadata(asset.amount, asset.metadata).toFormat()}
</p>
<div className='flex flex-col items-center text-base font-bold'>
<ValueViewComponent view={assetBalance.value} showDenom={false} />
</div>
</TableCell>
<TableCell className='w-1/3 text-center font-mono'>
<div className='flex flex-col'>
<p className='text-base font-bold'>
{asset.usdcValue == 0 ? '$–' : `$${displayUsd(asset.usdcValue)}`}
{assetBalance.usdcValue == 0
? '$–'
: `$${displayUsd(assetBalance.usdcValue)}`}
</p>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
})}
);
})}
</TableBody>
</Table>
</div>
))}
</div>
);
}
26 changes: 11 additions & 15 deletions apps/webapp/src/components/send/ibc/ibc-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,24 @@ import InputToken from '../../shared/input-token';
import { sendValidationErrors } from '../../../state/send';
import { useMemo } from 'react';
import { LoaderFunction, useLoaderData } from 'react-router-dom';
import { AccountBalance, getBalancesByAccount } from '../../../fetchers/balances';
import { AssetBalance, getAssetBalances } from '../../../fetchers/balances';
import { penumbraAddrValidation } from '../helpers';

export const IbcAssetBalanceLoader: LoaderFunction = async (): Promise<AccountBalance[]> => {
const balancesByAccount = await getBalancesByAccount();
export const IbcAssetBalanceLoader: LoaderFunction = async (): Promise<AssetBalance[]> => {
const assetBalances = await getAssetBalances();

if (balancesByAccount[0]) {
if (assetBalances[0]) {
// set initial account if accounts exist and asset if account has asset list
useStore.setState(state => {
state.ibc.selection = {
address: balancesByAccount[0]?.address,
accountIndex: balancesByAccount[0]?.index,
asset: balancesByAccount[0]?.balances[0],
};
state.ibc.selection = assetBalances[0];
});
}

return balancesByAccount;
return assetBalances;
};

export default function IbcForm() {
const accountBalances = useLoaderData() as AccountBalance[];
const assetBalances = useLoaderData() as AssetBalance[];
const { toast } = useToast();
const {
sendIbcWithdraw,
Expand All @@ -42,8 +38,8 @@ export default function IbcForm() {
} = useStore(ibcSelector);

const validationErrors = useMemo(() => {
return sendValidationErrors(selection?.asset, amount, destinationChainAddress);
}, [selection?.asset, amount, destinationChainAddress]);
return sendValidationErrors(selection, amount, destinationChainAddress);
}, [selection, amount, destinationChainAddress]);

return (
<form
Expand Down Expand Up @@ -71,7 +67,7 @@ export default function IbcForm() {
checkFn: () => validationErrors.amountErr,
},
]}
balances={accountBalances}
balances={assetBalances}
/>
<ChainSelector />
<InputBlock
Expand All @@ -95,7 +91,7 @@ export default function IbcForm() {
!Number(amount) ||
!destinationChainAddress ||
!!Object.values(validationErrors).find(Boolean) ||
!selection?.asset
!selection
}
>
Send
Expand Down
4 changes: 2 additions & 2 deletions apps/webapp/src/components/send/receive.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { SelectAccount } from '@penumbra-zone/ui';
import { getAccountAddr } from '../../fetchers/address';
import { getAddrByIndex } from '../../fetchers/address';

export const Receive = () => {
return (
<div className='pb-3 md:pb-5'>
<SelectAccount getAccount={getAccountAddr} />
<SelectAccount getAddrByIndex={getAddrByIndex} />
</div>
);
};
Loading

0 comments on commit 12cd517

Please sign in to comment.