Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dw): parse tx code + fix activities #2826

Merged
merged 4 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';

interface ErrorBoundaryProps {
fallback?: React.ReactNode;
children: React.ReactNode;
}

export class ErrorBoundary extends React.Component<
ErrorBoundaryProps,
{ hasError: boolean }
> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError() {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback;
}

return this.props.children;
}
}
7 changes: 5 additions & 2 deletions packages/apps/dev-wallet/src/modules/db/backup/backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,12 @@ export const importBackup =
`Database version mismatch: expected ${db.version} but got ${backup.db_version}; WIP: we need to add a migration path here`,
);
}
const tables = Object.keys(backup.data) as (keyof IDBBackup['data'])[];
const tables = Object.keys(backup.data).filter(
(name) => !name.includes(':'),
) as (keyof IDBBackup['data'])[];
console.log('Importing backup', tables);
const transaction = db.transaction(tables, 'readwrite');

console.log('transaction', transaction);
await importContacts(db, backup.data.contact, transaction);
const networkRemap = await importNetworks(
db,
Expand Down
18 changes: 18 additions & 0 deletions packages/apps/dev-wallet/src/modules/wallet/wallet.hook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ export const useWallet = () => {
[context.accounts, context.contacts],
);

const getAccountAlias = useCallback(
(address: string) => {
const account = context.accounts.find((a) => a.address === address);
if (account) {
return account.alias;
}
const contact = context.contacts.find(
(c) => c.account.address === address,
);
if (contact) {
return contact.name;
}
return '';
},
[context.accounts, context.contacts],
);

const getPublicKeyData = useCallback(
(publicKey: string) => {
if (!context.keySources) return null;
Expand Down Expand Up @@ -483,5 +500,6 @@ export const useWallet = () => {
accounts,
watchAccounts,
getKeyAlias,
getAccountAlias,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,35 @@ export function ActivityTable({ activities }: { activities: IActivity[] }) {
console.log('variables', variables);
const data = useMemo(
() =>
activities.map((activity) => ({
...activity,
open: (
<Link
to={`/transfer?activityId=${activity.uuid}`}
className={noStyleLinkClass}
style={{ textDecoration: 'underline' }}
>
<Text variant="code">{shorten(activity.uuid)}</Text>
</Link>
),
sender: shorten(activity.data.transferData.senderAccount.address, 6),
amount: activity.data.transferData.receivers.reduce(
(acc, { amount }) => {
return acc + parseFloat(amount);
},
0,
),
receivers: activity.data.transferData.receivers
.map((receiver) => shorten(receiver.address, 6))
.join(' | '),
})),
!activities
? []
: activities
.filter((activity) => activity?.data?.transferData?.senderAccount)
.map((activity) => ({
...activity,
open: (
<Link
to={`/transfer?activityId=${activity.uuid}`}
className={noStyleLinkClass}
style={{ textDecoration: 'underline' }}
>
<Text variant="code">{shorten(activity.uuid)}</Text>
</Link>
),
sender: shorten(
activity.data.transferData.senderAccount?.address ?? '',
6,
),
amount: activity.data.transferData.receivers.reduce(
(acc, { amount }) => {
return acc + parseFloat(amount);
},
0,
),
receivers: activity.data.transferData.receivers
.map((receiver) => shorten(receiver?.address ?? '', 6))
.join(' | '),
})),
[activities],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function ActivitiesPage() {
</Stack>
}
>
{activities.length > 0 && <ActivityTable activities={activities} />}
<ActivityTable activities={activities} />
</TabItem>
</Tabs>
</Stack>
Expand Down
2 changes: 1 addition & 1 deletion packages/apps/dev-wallet/src/pages/plugins/plugins.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export function Plugins() {
<Stack gap={'sm'} alignItems={'center'}>
<div style={{ display: 'inline-block' }}>
<div className={pluginIconClass}>
{getInitials(plugin.name).toUpperCase()}
{getInitials(plugin.shortName).toUpperCase()}
</div>
</div>
{plugin.name}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { CopyButton } from '@/Components/CopyButton/CopyButton';
import { ErrorBoundary } from '@/Components/ErrorBoundary/ErrorBoundary';
import { ITransaction } from '@/modules/transaction/transaction.repository';
import { useWallet } from '@/modules/wallet/wallet.hook';
import { shorten, toISOLocalDateTime } from '@/utils/helpers';
import { shortenPactCode } from '@/utils/parsedCodeToPact';
import { IPactCommand } from '@kadena/client';
import { MonoTextSnippet } from '@kadena/kode-icons/system';
import { Button, Heading, Notification, Stack, Text } from '@kadena/kode-ui';
import { execCodeParser } from '@kadena/pactjs-generator';
import classNames from 'classnames';
import { useMemo, useState } from 'react';
import { CodeView } from './code-components/CodeView';
import { Label, Value } from './helpers';
import { RenderSigner } from './Signer';
import { cardClass, codeClass, textEllipsis } from './style.css';
Expand Down Expand Up @@ -36,6 +39,13 @@ export function CommandView({
[command, getPublicKeyData],
);

const parsedCode = useMemo(() => {
if ('exec' in command.payload) {
return execCodeParser(command.payload.exec.code);
}
return [];
}, [command.payload]);

const externalSigners = signers.filter((signer) => !signer.info);
const internalSigners = signers.filter((signer) => signer.info);
const [showShortenCode, setShowShortenCode] = useState(true);
Expand All @@ -47,6 +57,9 @@ export function CommandView({
</Stack>
{'exec' in command.payload && (
<>
<ErrorBoundary>
<CodeView codes={parsedCode} command={command} />
</ErrorBoundary>
<Stack gap={'sm'} flexDirection={'column'}>
<Stack gap={'sm'} justifyContent={'space-between'}>
<Heading variant="h4">Code</Heading>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { useWallet } from '@/modules/wallet/wallet.hook';
import { shorten } from '@/utils/helpers';
import { parseArg } from '@/utils/parsedCodeToPact';
import { IPactCommand } from '@kadena/client';
import { Badge, Card, Heading, Stack, Text } from '@kadena/kode-ui';
import { IParsedCode } from '@kadena/pactjs-generator';

const decoration = {
shortening: Infinity,
withIndent: 0,
breakLines: false,
};

export function CodeView({
codes,
command,
}: {
codes?: IParsedCode[];
command: IPactCommand;
}) {
const { getAccountAlias } = useWallet();
const getAccount = (address: string) => {
const value = address.replace(/"/gi, '');
const alias = getAccountAlias(value);
const shortAddress = shorten(value, 20);
if (!alias) return shortAddress;
console.log('alias', alias);
return (
<Stack gap={'sm'} flexWrap="wrap">
<Badge size="sm">{alias}</Badge>
<Text bold color="emphasize">
{shortAddress}
</Text>
</Stack>
);
};

const describes = !codes
? []
: codes
.map((code) => {
if (code.function.module === 'coin' && !code.function.namespace) {
if (code.function.name === 'transfer') {
const [sender, receiver, amount] = code.args;
const senderAddress = parseArg(sender, decoration);
const receiverAddress = parseArg(receiver, decoration);
return (
<Stack gap={'sm'} flexDirection={'column'}>
<Heading variant="h5">Transfer</Heading>
<Stack gap={'sm'} flexWrap="wrap">
<Text>from</Text>
<Text bold color="emphasize">
{getAccount(senderAddress)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>to</Text>
<Text bold color="emphasize">
{getAccount(receiverAddress)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>amount</Text>
<Text bold color="emphasize">
{parseArg(amount, decoration)}
</Text>
</Stack>
</Stack>
);
}
if (code.function.name === 'transfer-create') {
const [sender, receiver, , amount] = code.args;
const senderAddress = parseArg(sender, decoration);
const receiverAddress = parseArg(receiver, decoration);
return (
<Stack gap={'sm'} flexDirection={'column'}>
<Heading variant="h5">Transfer</Heading>
<Stack gap={'sm'} flexWrap="wrap">
<Text>from</Text>
<Text bold color="emphasize">
{getAccount(senderAddress)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>to</Text>
<Text bold color="emphasize">
{getAccount(receiverAddress)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>amount</Text>
<Text bold color="emphasize">
{parseArg(amount, decoration)}
</Text>
</Stack>
</Stack>
);
}

if (code.function.name === 'transfer-crosschain') {
const [sender, receiver, , targetChain, amount] = code.args;
const senderAddress = parseArg(sender, decoration);
const receiverAddress = parseArg(receiver, decoration);
return (
<Stack gap={'sm'} flexDirection={'column'}>
<Heading variant="h5">Cross-chain Transfer</Heading>
<Stack gap={'sm'} flexWrap="wrap">
<Text>from</Text>
<Text bold color="emphasize">
{getAccount(senderAddress)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>to</Text>
<Text bold color="emphasize">
{getAccount(receiverAddress)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>amount</Text>
<Text bold color="emphasize">
{parseArg(amount, decoration)}
</Text>
</Stack>
<Stack gap={'sm'} flexWrap="wrap">
<Text>target chain</Text>
<Text bold color="emphasize">
{parseArg(targetChain, decoration)}
</Text>
</Stack>
</Stack>
);
}
}
return null;
})
.filter(Boolean);

return describes.length > 0 ? (
<Stack flexDirection={'column'} gap={'md'}>
<>
{describes.map((e) => (
<Card fullWidth>{e}</Card>
))}
{command && (
<Card fullWidth>
<Stack gap={'sm'} flexDirection={'column'}>
<Heading variant="h5">Max Gas Cost</Heading>
<Text bold color="emphasize">
{(command.meta.gasLimit ?? 0) * (command.meta.gasPrice ?? 0)}{' '}
KDA
</Text>
</Stack>
</Card>
)}
</>
</Stack>
) : null;
}
3 changes: 3 additions & 0 deletions packages/apps/dev-wallet/src/pages/transfer/transfer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ export function Transfer() {
accountId={accountId}
activityId={urlActivityId}
onSubmit={async (data, redistribution) => {
if (!data.senderAccount) {
throw new Error('Sender account not found');
}
const receivers = data.receivers.filter(
Boolean,
) as Required<IReceiver>[];
Expand Down
2 changes: 1 addition & 1 deletion packages/apps/dev-wallet/src/utils/parsedCodeToPact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface IDecoration {
breakLines?: boolean;
}

const parseArg = (
export const parseArg = (
arg: IParsedCode['args'][number],
decoration: Required<IDecoration>,
): string => {
Expand Down
Loading