From be30009eeac0aa9442cf0d262bd52cd5da9868fa Mon Sep 17 00:00:00 2001 From: Javad Khalilian Date: Fri, 25 Oct 2024 16:52:51 +0200 Subject: [PATCH] refactor(dw): transactions (#2618) * refactor(dw): transactions * chore: clean up * feat(dw): faund button --- .../AccountBalanceDistribution.tsx | 3 +- .../components/ChainBalance.tsx | 22 +- .../components/ChainList.tsx | 3 +- .../processChainAccounts.ts | 2 +- .../FundOnTestnet/FundOnTestnet.tsx | 57 +++ .../transaction/transaction.repository.ts | 1 + .../transaction/transaction.service.ts | 161 ++++++- .../pages/account/Components/Redistribute.tsx | 13 +- .../dev-wallet/src/pages/account/account.tsx | 31 +- .../src/pages/transaction/Transaction.tsx | 382 ++-------------- .../components/ExpandedTransaction.tsx | 41 +- .../transaction/components/TxContainer.tsx | 153 +++++++ .../pages/transaction/components/TxList.tsx | 416 ++++++------------ .../transaction/components/TxMinimized.tsx | 64 +++ .../transaction/components/TxPipeLine.tsx | 384 ++++++++-------- .../pages/transaction/components/style.css.ts | 6 + .../transfer-v2/Steps/Redistribution.tsx | 93 ---- .../src/pages/transfer-v2/transfer-v2.tsx | 12 +- 18 files changed, 860 insertions(+), 984 deletions(-) create mode 100644 packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx create mode 100644 packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx create mode 100644 packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx delete mode 100644 packages/apps/dev-wallet/src/pages/transfer-v2/Steps/Redistribution.tsx diff --git a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/AccountBalanceDistribution.tsx b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/AccountBalanceDistribution.tsx index ab21624e37..28066235f8 100644 --- a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/AccountBalanceDistribution.tsx +++ b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/AccountBalanceDistribution.tsx @@ -3,6 +3,7 @@ import { isWatchedAccount, IWatchedAccount, } from '@/modules/account/account.repository'; +import { ITransaction } from '@/modules/transaction/transaction.repository'; import { useWallet } from '@/modules/wallet/wallet.hook'; import { createRedistributionTxs, @@ -23,7 +24,7 @@ interface IProps extends PropsWithChildren { balance: number; }[]; overallBalance: string; - fundAccount: (chainId: ChainId) => Promise; + fundAccount: (chainId: ChainId) => Promise; account: IAccount | IWatchedAccount; onRedistribution: (groupId: string) => void; } diff --git a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainBalance.tsx b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainBalance.tsx index ea95068788..93e9981958 100644 --- a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainBalance.tsx +++ b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainBalance.tsx @@ -1,6 +1,8 @@ +import { FundOnTestnetButton } from '@/Components/FundOnTestnet/FundOnTestnet'; +import { ITransaction } from '@/modules/transaction/transaction.repository'; import { useWallet } from '@/modules/wallet/wallet.hook'; import { ChainId } from '@kadena/client'; -import { Button, Stack, Text, TextField } from '@kadena/kode-ui'; +import { Stack, Text, TextField } from '@kadena/kode-ui'; import { assignInlineVars } from '@vanilla-extract/dynamic'; import classNames from 'classnames'; import type { FC, PropsWithChildren } from 'react'; @@ -18,8 +20,8 @@ import { interface IProps extends PropsWithChildren { chainAccount: IViewChain; - chainId: string; - fundAccount?: (chainId: ChainId) => Promise; + chainId: ChainId; + fundAccount?: (chainId: ChainId) => Promise; editable?: boolean; onItemChange?: (key: string, value: any) => void; } @@ -61,14 +63,12 @@ export const ChainBalance: FC = ({ Chain {chainId} {!editable && activeNetwork?.faucetContract && fundAccount && ( - + + + )} diff --git a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainList.tsx b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainList.tsx index 3975f9e64d..515978fbed 100644 --- a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainList.tsx +++ b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/components/ChainList.tsx @@ -1,3 +1,4 @@ +import { ITransaction } from '@/modules/transaction/transaction.repository'; import { ChainId } from '@kadena/client'; import { Stack } from '@kadena/kode-ui'; import type { FC, PropsWithChildren } from 'react'; @@ -6,7 +7,7 @@ import { ChainBalance } from './ChainBalance'; interface IProps extends PropsWithChildren { chains: IViewChain[]; - fundAccount?: (chainId: ChainId) => Promise; + fundAccount?: (chainId: ChainId) => Promise; editable?: boolean; onItemChange?: (key: string, value: any) => void; } diff --git a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/processChainAccounts.ts b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/processChainAccounts.ts index 6c3d50f796..97f9ad19f4 100644 --- a/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/processChainAccounts.ts +++ b/packages/apps/dev-wallet/src/Components/AccountBalanceDistribution/processChainAccounts.ts @@ -1,7 +1,7 @@ import { ChainId } from '@kadena/client'; export interface IViewChain { - chainId: string; + chainId: ChainId; percentage?: number; balance?: number; } diff --git a/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx b/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx new file mode 100644 index 0000000000..2180cf0db4 --- /dev/null +++ b/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx @@ -0,0 +1,57 @@ +import { IAccount } from '@/modules/account/account.repository'; +import { syncAccount } from '@/modules/account/account.service'; +import { ITransaction } from '@/modules/transaction/transaction.repository'; +import { useWallet } from '@/modules/wallet/wallet.hook'; +import { TxContainer } from '@/pages/transaction/components/TxContainer'; +import { ChainId } from '@kadena/client'; +import { Button } from '@kadena/kode-ui'; +import { useState } from 'react'; + +export function FundOnTestnetButton({ + account, + chainId, + fundAccountHandler, +}: { + account?: IAccount; + chainId?: ChainId; + fundAccountHandler: (chainId: ChainId) => Promise; +}) { + const [fundTx, setFundTx] = useState(); + const { syncAllAccounts } = useWallet(); + + return ( + <> + {!fundTx && ( + + )} + + {fundTx && ( + { + setFundTx(tx); + if (account) { + syncAccount(account); + } else { + syncAllAccounts(); + } + if (tx.result?.result.status === 'success') { + setTimeout(() => setFundTx(undefined), 2000); + } + }} + /> + )} + + ); +} diff --git a/packages/apps/dev-wallet/src/modules/transaction/transaction.repository.ts b/packages/apps/dev-wallet/src/modules/transaction/transaction.repository.ts index 9bfdcbe405..182d00504c 100644 --- a/packages/apps/dev-wallet/src/modules/transaction/transaction.repository.ts +++ b/packages/apps/dev-wallet/src/modules/transaction/transaction.repository.ts @@ -36,6 +36,7 @@ export type ITransaction = { done?: boolean; }; purpose?: { type: string; data: Record }; + result?: ICommandResult; } & ( | { height?: number; diff --git a/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts b/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts index 9c94e4cd73..5725dfe2f9 100644 --- a/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts +++ b/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts @@ -1,4 +1,16 @@ -import { ChainId, IUnsignedCommand } from '@kadena/client'; +import { + ChainId, + createTransaction, + IClient, + ICommand, + IUnsignedCommand, +} from '@kadena/client'; +import { + composePactCommand, + continuation, + setMeta, + setNetworkId, +} from '@kadena/client/fp'; import { UUID } from '../types'; import { ITransaction, transactionRepository } from './transaction.repository'; @@ -31,3 +43,150 @@ export async function addTransaction({ await transactionRepository.addTransaction(tx); return tx; } + +export const onSubmitTransaction = async ( + tx: ITransaction, + client: IClient, + onUpdate: (tx: ITransaction) => void, +) => { + let updatedTx = await client + .preflight({ + cmd: tx.cmd, + sigs: tx.sigs, + hash: tx.hash, + } as ICommand) + .then(async (result) => { + console.log('preflight', result); + const updatedTx = { + ...tx, + status: 'preflight', + preflight: result, + request: undefined, + } as ITransaction; + await transactionRepository.updateTransaction(updatedTx); + return updatedTx; + }); + onUpdate(updatedTx); + if ( + 'result' in updatedTx || + ('result' in updatedTx && updatedTx.result!.result.status === 'success') + ) { + return updatedTx; + } + if (updatedTx.preflight?.result.status === 'failure') { + return updatedTx; + } + updatedTx = await client + .submitOne({ + cmd: tx.cmd, + sigs: tx.sigs, + hash: tx.hash, + } as ICommand) + .then(async (request) => { + updatedTx = { + ...updatedTx, + status: 'submitted', + request, + } as ITransaction; + await transactionRepository.updateTransaction(updatedTx); + return updatedTx; + }); + onUpdate(updatedTx); + + updatedTx = await client.pollOne(updatedTx.request!).then(async (result) => { + updatedTx = { + ...updatedTx, + status: result.result.status, + result, + } as ITransaction; + await transactionRepository.updateTransaction(updatedTx); + return updatedTx; + }); + onUpdate(updatedTx); + if ( + updatedTx.status === 'success' && + updatedTx.result?.continuation && + updatedTx.continuation && + updatedTx.continuation.autoContinue + ) { + if (updatedTx.continuation.proof === undefined) { + const request = updatedTx.request; + const crossChainId = updatedTx.continuation.crossChainId; + const continuationData = updatedTx.continuation; + const contResult = updatedTx.result; + updatedTx = { + ...updatedTx, + continuation: { + ...updatedTx.continuation, + proof: null, + }, + } as ITransaction; + await transactionRepository.updateTransaction(updatedTx); + onUpdate(updatedTx); + let proof = null; + if (crossChainId) { + console.log('pollCreateSpv', request, crossChainId); + proof = await client.pollCreateSpv(request, crossChainId); + updatedTx = { + ...updatedTx, + continuation: { + ...updatedTx.continuation, + proof, + }, + } as ITransaction; + await transactionRepository.updateTransaction(updatedTx); + } + // TODO: this is very specific to the crosschain-transfer. we should make it more generic + const continuationTx = composePactCommand( + continuation({ + pactId: contResult.continuation!.pactId, + step: contResult.continuation!.step + 1, + proof, + rollback: false, + data: {}, + }), + setMeta({ + chainId: crossChainId || request.chainId, + senderAccount: 'kadena-xchain-gas', + gasLimit: 850, + }), + setNetworkId(request.networkId), + )(); + const contTx = await addTransaction({ + transaction: createTransaction(continuationTx), + networkUUID: tx.networkUUID, + profileId: updatedTx.profileId, + groupId: `${updatedTx.groupId}:continuation`, + }); + updatedTx = { + ...updatedTx, + continuation: { + ...continuationData, + continuationTxId: contTx.uuid, + }, + }; + await transactionRepository.updateTransaction(updatedTx); + onUpdate(updatedTx); + await onSubmitTransaction(contTx, client, (tx) => { + updatedTx = { + ...updatedTx, + continuation: { + ...updatedTx.continuation!, + tx, + }, + }; + onUpdate(updatedTx); + }); + updatedTx = { + ...updatedTx, + continuation: { + ...updatedTx.continuation!, + done: true, + }, + }; + await transactionRepository.updateTransaction(updatedTx); + onUpdate(updatedTx); + } + } + return updatedTx; +}; diff --git a/packages/apps/dev-wallet/src/pages/account/Components/Redistribute.tsx b/packages/apps/dev-wallet/src/pages/account/Components/Redistribute.tsx index a8e55432e3..41a2a52641 100644 --- a/packages/apps/dev-wallet/src/pages/account/Components/Redistribute.tsx +++ b/packages/apps/dev-wallet/src/pages/account/Components/Redistribute.tsx @@ -9,19 +9,10 @@ export function Redistribute({ groupId: string; onDone: () => void; }) { - const [reTxs, , , reloadTxs] = useAsync( + const [reTxs] = useAsync( async (gid) => transactionRepository.getTransactionsByGroup(gid), [groupId], ); if (!reTxs) return null; - return ( - { - console.log('update'); - reloadTxs(); - }} - txs={reTxs} - onDone={onDone} - /> - ); + return tx.uuid)} onDone={onDone} />; } diff --git a/packages/apps/dev-wallet/src/pages/account/account.tsx b/packages/apps/dev-wallet/src/pages/account/account.tsx index 5f3d39f643..b1c73fee00 100644 --- a/packages/apps/dev-wallet/src/pages/account/account.tsx +++ b/packages/apps/dev-wallet/src/pages/account/account.tsx @@ -4,6 +4,7 @@ import { fundAccount } from '@/modules/account/account.service'; import { AccountBalanceDistribution } from '@/Components/AccountBalanceDistribution/AccountBalanceDistribution'; import { ConfirmDeletion } from '@/Components/ConfirmDeletion/ConfirmDeletion'; +import { FundOnTestnetButton } from '@/Components/FundOnTestnet/FundOnTestnet'; import { usePrompt } from '@/Components/PromptProvider/Prompt'; import { QRCode } from '@/Components/QRCode/QRCode'; import { @@ -54,14 +55,16 @@ export function AccountPage() { } const fundAccountHandler = async (chainId: ChainId) => { - if ('watched' in account && account.watched) return; + if ('watched' in account && account.watched) { + throw new Error('Can not fund watched account'); + } if (!keyset || !('principal' in keyset)) { throw new Error('No keyset found'); } if (!activeNetwork) { throw new Error('No active network found'); } - const { groupId } = await fundAccount({ + const tx = await fundAccount({ address: account?.address ?? keyset.principal, chainId, keyset, @@ -69,7 +72,7 @@ export function AccountPage() { network: activeNetwork, }); - navigate(`/transaction/${groupId}`); + return tx; }; const isOwnedAccount = !isWatchedAccount(account) && account.profileId === profile?.uuid; @@ -95,13 +98,12 @@ export function AccountPage() { )} {isOwnedAccount && ( - + + )} {asset.contract === 'coin' && ( - + )} diff --git a/packages/apps/dev-wallet/src/pages/transaction/Transaction.tsx b/packages/apps/dev-wallet/src/pages/transaction/Transaction.tsx index 8840ad5fdb..cfe0ec0203 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/Transaction.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/Transaction.tsx @@ -1,365 +1,35 @@ -import { - ITransaction, - TransactionStatus, - transactionRepository, -} from '@/modules/transaction/transaction.repository'; -import { useWallet } from '@/modules/wallet/wallet.hook'; -import { shorten } from '@/utils/helpers'; -import { ICommand, IUnsignedCommand } from '@kadena/client'; -import { MonoBrightness1 } from '@kadena/kode-icons/system'; -import { - Button, - Notification, - Stack, - TabItem, - Tabs, - Text, -} from '@kadena/kode-ui'; -import { isSignedCommand } from '@kadena/pactjs'; -import classNames from 'classnames'; -import { useCallback, useEffect, useState } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; -import { CommandView } from './components/CommandView'; -import { SubmittedStatus } from './components/SubmittedStatus'; -import { - failureClass, - pendingClass, - successClass, -} from './components/style.css'; -import { tabStyle } from './style.css'; +import { transactionRepository } from '@/modules/transaction/transaction.repository'; -const steps: TransactionStatus[] = [ - 'initiated', - 'signed', - 'preflight', - 'submitted', - 'success', - 'failure', - 'persisted', -]; +import { useAsync } from '@/utils/useAsync'; +import { Heading, Stack, Text } from '@kadena/kode-ui'; +import { useParams } from 'react-router-dom'; +import { TxList } from './components/TxList'; -const getOverallStep = (list: ITransaction[]) => - list.reduce( - (acc: [TransactionStatus, number], tx, idx) => { - const [step] = acc; - if (steps.indexOf(tx.status) < steps.indexOf(step)) { - return [tx.status, idx] as [TransactionStatus, number]; - } - return acc; - }, - ['persisted', 0] as const, - ); - -export function Transaction({ groupId }: { groupId?: string }) { - const [Txs, setTxs] = useState(null); - const [step, setStep] = useState(null); - const [selectedTxIndex, setSelectedTxIndex] = useState(0); - const [error, setError] = useState(null); - const [viewStep, setViewStep] = useState<'transaction' | 'result'>('result'); - const navigate = useNavigate(); - const { sign, client } = useWallet(); - - const loadTxs = useCallback(async (groupId: string) => { - const list = await transactionRepository.getTransactionsByGroup(groupId); - const [overallStep, firstTx] = getOverallStep(list); - setTxs(list); - setSelectedTxIndex(firstTx); - setStep(overallStep); - return list; - }, []); - - useEffect(() => { - if (groupId) { - loadTxs(groupId); - } - }, [groupId, loadTxs]); - - const patchTransaction = useCallback( - async (original: ITransaction, patch: Partial) => { - if (original && Txs) { - const updated = { - ...original, - ...patch, - } as ITransaction; - await transactionRepository.updateTransaction(updated); - return loadTxs(groupId!); - } - }, - [Txs, groupId, loadTxs], - ); - - const submitTxs = useCallback( - async (list: ITransaction[]) => { - if (!groupId) return; - if (!list.every(isSignedCommand)) return; - const preflightValidation = await Promise.all( - list.map((tx) => - client - .preflight({ - cmd: tx.cmd, - sigs: tx.sigs, - hash: tx.hash, - } as ICommand) - .then(async (result) => { - await transactionRepository.updateTransaction({ - ...tx, - status: 'preflight', - preflight: result, - request: undefined, - }); - return result.result.status === 'success'; - }), - ), - ); - if (preflightValidation.some((isValid) => !isValid)) { - setError('Preflight failed'); - return; - } - const listForSubmission = await loadTxs(groupId); - await Promise.all( - listForSubmission.map((tx) => - client - .submitOne({ - cmd: tx.cmd, - sigs: tx.sigs, - hash: tx.hash, - } as ICommand) - .then(async (request) => { - const updatedTx = { - ...tx, - status: 'submitted', - request, - } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - await loadTxs(groupId); - return request; - }) - .catch((e) => { - setError(e && e.message ? e.message : e ?? 'Unknown error'); - }), - ), - ); - }, - [groupId, loadTxs], - ); - - useEffect(() => { - async function run() { - if (step === 'submitted' && groupId) { - const listForSubmission = await loadTxs(groupId); - await Promise.all( - listForSubmission.map((tx) => - tx.request - ? client - .pollOne(tx.request) - .then(async (result) => { - const updatedTx = { - ...tx, - status: result.result.status, - result, - } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - await loadTxs(groupId); - return result; - }) - .catch((e) => { - setError(e && e.message ? e.message : e ?? 'Unknown error'); - }) - : null, - ), - ); - } - } - run(); - }, [step, groupId, loadTxs]); - - if (!Txs || !groupId) return null; - - const resultStep = ['success', 'failure', 'submitted'].includes(step!); - - const signAll = async () => { - const signed = (await sign(Txs)) as (IUnsignedCommand | ICommand)[]; - - const updatedTxs = Txs.map((tx) => { - const signedTx = signed.find(({ hash }) => hash === tx.hash); - if (!signedTx) return tx; - return { - ...tx, - ...signedTx, - status: isSignedCommand(signedTx) - ? steps.indexOf(tx.status) < steps.indexOf('signed') - ? 'signed' - : tx.status - : tx.status, - } as ITransaction; - }); - - await updatedTxs.map(transactionRepository.updateTransaction); - loadTxs(groupId!); - }; - - const Stepper = () => ( - - - - +export const TransactionPage = () => { + const { groupId } = useParams(); + const [txs = []] = useAsync( + (gid) => + gid + ? transactionRepository.getTransactionsByGroup(gid) + : Promise.resolve([]), + [groupId], ); - - if ( - ['success', 'failure', 'submitted'].includes(step!) && - viewStep === 'result' - ) { - return ( - - - - setSelectedTxIndex(key as number)} - > - {Txs.map((tx, index) => ( - - {index + 1}: - {shorten(tx.hash)} - - - - } - > - - - ))} - - - ); - } return ( - - - - {error && {error}} - - - setSelectedTxIndex(+key as number)} - > - {Txs.map((tx, index) => ( - - {index + 1}: - {shorten(tx.hash)} - = steps.indexOf('signed') && - successClass, - )} - /> - - } - > - { - patchTransaction(tx, { - sigs, - status: sigs.every((data) => data?.sig) - ? steps.indexOf(tx.status) < steps.indexOf('signed') - ? 'signed' - : tx.status - : tx.status, - }); - }} - /> - - ))} - + + + Transactions + {txs.length === 0 && No transactions} + {txs.length >= 2 && ( + This is a group of {txs.length} Transactions + )} - {/* { - patchTransaction({ - sigs, - status: sigs.every((data) => data?.sig) - ? steps.indexOf(transaction.status) < steps.indexOf('signed') - ? 'signed' - : transaction.status - : transaction.status, - }); + { + console.log('done'); }} - /> */} - - - - - - + txIds={txs.map((tx) => tx.uuid)} + showExpanded={txs.length === 1} + /> ); -} - -export const TransactionPage = () => { - const { groupId } = useParams(); - return ; }; diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/ExpandedTransaction.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/ExpandedTransaction.tsx index c7e3911d59..81724c0c4d 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/ExpandedTransaction.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/components/ExpandedTransaction.tsx @@ -4,7 +4,6 @@ import { ContextMenu, ContextMenuItem, DialogContent, - DialogFooter, DialogHeader, Heading, Notification, @@ -33,11 +32,13 @@ export function ExpandedTransaction({ onSign, sendDisabled, onSubmit, + showTitle, }: { transaction: ITransaction; onSign: (sig: ITransaction['sigs']) => void; onSubmit: () => Promise; sendDisabled?: boolean; + showTitle?: boolean; }) { const { sign } = useWallet(); @@ -83,7 +84,7 @@ export function ExpandedTransaction({ <> - View Transaction + {showTitle && View Transaction} @@ -112,6 +113,24 @@ export function ExpandedTransaction({ flexDirection={'column'} className={panelClass} > + {statusPassed(transaction.status, 'success') && + (!transaction.continuation?.autoContinue || + (contTx && statusPassed(contTx.status, 'success'))) && ( + + + Transaction is successful + + + )} + {transaction.status === 'failure' && + (!transaction.continuation?.autoContinue || + (contTx && contTx.status === 'failure')) && ( + + + Transaction is failed + + + )} @@ -212,24 +231,6 @@ export function ExpandedTransaction({ - - - - {statusPassed(transaction.status, 'success') && - (!transaction.continuation?.autoContinue || - (contTx && statusPassed(contTx.status, 'success'))) && ( - - Transaction is successful - - )} - - - ); } diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx new file mode 100644 index 0000000000..275f8093bb --- /dev/null +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx @@ -0,0 +1,153 @@ +import { + ITransaction, + transactionRepository, +} from '@/modules/transaction/transaction.repository'; +import * as transactionService from '@/modules/transaction/transaction.service'; +import { useWallet } from '@/modules/wallet/wallet.hook'; +import { IUnsignedCommand } from '@kadena/client'; +import { Dialog } from '@kadena/kode-ui'; +import { isSignedCommand } from '@kadena/pactjs'; +import React, { useCallback, useEffect, useState } from 'react'; +import { ExpandedTransaction } from './ExpandedTransaction'; +import { containerClass } from './style.css'; +import { TxMinimized } from './TxMinimized'; +import { steps } from './TxPipeLine'; +import { TxTile } from './TxTile'; + +export const TxContainer = React.memo( + ({ + transaction, + as, + sendDisabled, + onUpdate, + onDone, + }: { + transaction: ITransaction; + as: 'tile' | 'expanded' | 'minimized'; + sendDisabled?: boolean; + onUpdate?: (tx: ITransaction) => void; + onDone?: (tx: ITransaction) => void; + }) => { + const [localTransaction, setLocalTransaction] = + useState(null); + const [expandedModal, setExpandedModal] = useState(false); + const { sign, client } = useWallet(); + + useEffect(() => { + if (!transaction) return; + transactionRepository + .getTransaction(transaction.uuid) + .then(setLocalTransaction); + }, [transaction]); + + const onSign = async (tx: ITransaction) => { + const signed = (await sign(tx)) as IUnsignedCommand; + const updated = { + ...tx, + ...signed, + status: isSignedCommand(signed) + ? steps.indexOf(tx.status) < steps.indexOf('signed') + ? 'signed' + : tx.status + : tx.status, + } as ITransaction; + await transactionRepository.updateTransaction(updated); + setLocalTransaction(updated); + if (onUpdate) { + onUpdate(updated); + } + }; + + const onExpandedSign = + (tx: ITransaction) => async (sigs: ITransaction['sigs']) => { + const updated = { + ...tx, + sigs, + status: sigs.every((data) => data?.sig) + ? steps.indexOf(tx.status) < steps.indexOf('signed') + ? 'signed' + : tx.status + : tx.status, + } as ITransaction; + await transactionRepository.updateTransaction(updated); + setLocalTransaction(updated); + if (onUpdate) { + onUpdate(updated); + } + }; + + const onSubmit = useCallback( + async (tx: ITransaction) => { + const result = await transactionService.onSubmitTransaction( + tx, + client, + (updatedTx) => { + setLocalTransaction(updatedTx); + }, + ); + if (onUpdate) onUpdate(result); + if (onDone) onDone(result); + return result; + }, + [client, onDone, onUpdate], + ); + + if (!localTransaction) return null; + const renderExpanded = () => ( + onSubmit(localTransaction)} + sendDisabled={sendDisabled} + showTitle={as === 'tile'} + /> + ); + if (as === 'tile' || as === 'minimized') + return ( + <> + {expandedModal && ( + { + if (!isOpen) { + setExpandedModal(false); + } + }} + > + {renderExpanded()} + + )} + {as === 'tile' && ( + { + onSign(localTransaction); + }} + onSubmit={() => onSubmit(localTransaction)} + onView={async () => { + setExpandedModal(true); + }} + /> + )} + {as === 'minimized' && ( + { + onSign(localTransaction); + }} + onSubmit={() => onSubmit(localTransaction)} + onView={async () => { + setExpandedModal(true); + }} + /> + )} + + ); + + return renderExpanded(); + }, +); diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx index fc386d5b5a..1175839d88 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx @@ -3,315 +3,155 @@ import { transactionRepository, } from '@/modules/transaction/transaction.repository'; -import { Button, Dialog, Stack, Text } from '@kadena/kode-ui'; +import { Button, Stack, Text } from '@kadena/kode-ui'; import { useWallet } from '@/modules/wallet/wallet.hook'; -import { ICommand, IUnsignedCommand, createTransaction } from '@kadena/client'; -import { - composePactCommand, - continuation, - setMeta, - setNetworkId, -} from '@kadena/client/fp'; +import { ICommand, IUnsignedCommand } from '@kadena/client'; import { MonoSignature } from '@kadena/kode-icons/system'; import { isSignedCommand } from '@kadena/pactjs'; -import React from 'react'; -import { TxTile } from './TxTile'; -import { containerClass } from './style.css'; +import React, { useCallback, useEffect } from 'react'; import * as transactionService from '@/modules/transaction/transaction.service'; -import { ExpandedTransaction } from './ExpandedTransaction'; +import { TxContainer } from './TxContainer'; import { statusPassed, steps } from './TxPipeLine'; -export function TxList({ - txs, - onUpdate, - sendDisabled, - onDone, - showExpanded, -}: { - txs: ITransaction[]; - showExpanded?: boolean; - onUpdate: () => void; - sendDisabled?: boolean; - onDone?: () => void; -}) { - const [selectedTxIndex, setSelectedTxIndex] = React.useState< - number | undefined - >(undefined); - const { sign, client } = useWallet(); - const signAll = async () => { - const signed = (await sign(txs)) as (IUnsignedCommand | ICommand)[]; +export const TxList = React.memo( + ({ + txIds, + sendDisabled, + onDone, + showExpanded, + }: { + txIds: string[]; + showExpanded?: boolean; + sendDisabled?: boolean; + onDone?: () => void; + }) => { + const { sign, client } = useWallet(); + const [transactions, setTransactions] = React.useState([]); - const updatedTxs = txs.map((tx) => { - const signedTx = signed.find(({ hash }) => hash === tx.hash); - if (!signedTx) return tx; - return { - ...tx, - ...signedTx, - status: isSignedCommand(signedTx) - ? steps.indexOf(tx.status) < steps.indexOf('signed') - ? 'signed' - : tx.status - : tx.status, - } as ITransaction; - }); + useEffect(() => { + if (!txIds || txIds.length === 0) { + setTransactions([]); + return; + } + Promise.all(txIds.map(transactionRepository.getTransaction)).then( + setTransactions, + ); + }, [txIds]); - await updatedTxs.map(transactionRepository.updateTransaction); - onUpdate(); - }; + const updateTx = useCallback( + (updatedTx: ITransaction) => + setTransactions((prev) => + prev.map((prevTx) => + prevTx.uuid === updatedTx.uuid ? updatedTx : prevTx, + ), + ), + [], + ); - const onSign = async (tx: ITransaction) => { - const signed = (await sign(tx)) as IUnsignedCommand; - const updated = { - ...tx, - ...signed, - status: isSignedCommand(signed) - ? steps.indexOf(tx.status) < steps.indexOf('signed') - ? 'signed' - : tx.status - : tx.status, - } as ITransaction; - await transactionRepository.updateTransaction(updated); - onUpdate(); - }; + const signAll = async () => { + const txs = await Promise.all( + txIds.map(transactionRepository.getTransaction), + ); + const signed = (await sign(txs)) as (IUnsignedCommand | ICommand)[]; - const onSubmit = async (tx: ITransaction) => { - let updatedTx = await client - .preflight({ - cmd: tx.cmd, - sigs: tx.sigs, - hash: tx.hash, - } as ICommand) - .then(async (result) => { - console.log('preflight', result); - const updatedTx = { + const updatedTxs = txs.map((tx) => { + const signedTx = signed.find(({ hash }) => hash === tx.hash); + if (!signedTx) return tx; + return { ...tx, - status: 'preflight', - preflight: result, - request: undefined, - } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - return updatedTx; - }); - onUpdate(); - if ( - 'result' in updatedTx || - ('result' in updatedTx && updatedTx.result!.result.status === 'success') - ) { - return updatedTx; - } - if (updatedTx.preflight?.result.status === 'failure') { - return updatedTx; - } - updatedTx = await client - .submitOne({ - cmd: tx.cmd, - sigs: tx.sigs, - hash: tx.hash, - } as ICommand) - .then(async (request) => { - updatedTx = { - ...updatedTx, - status: 'submitted', - request, - } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - return updatedTx; - }); - onUpdate(); - - updatedTx = await client - .pollOne(updatedTx.request!) - .then(async (result) => { - updatedTx = { - ...updatedTx, - status: result.result.status, - result, + ...signedTx, + status: isSignedCommand(signedTx) + ? steps.indexOf(tx.status) < steps.indexOf('signed') + ? 'signed' + : tx.status + : tx.status, } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - return updatedTx; }); - onUpdate(); - if ( - updatedTx.status === 'success' && - updatedTx.result?.continuation && - updatedTx.continuation && - updatedTx.continuation.autoContinue - ) { - if (updatedTx.continuation.proof === undefined) { - const request = updatedTx.request; - const crossChainId = updatedTx.continuation.crossChainId; - const continuationData = updatedTx.continuation; - const contResult = updatedTx.result; - updatedTx = { - ...updatedTx, - continuation: { - ...updatedTx.continuation, - proof: null, - }, - } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - onUpdate(); - let proof = null; - if (crossChainId) { - console.log('pollCreateSpv', request, crossChainId); - proof = await client.pollCreateSpv(request, crossChainId); - updatedTx = { - ...updatedTx, - continuation: { - ...updatedTx.continuation, - proof, - }, - } as ITransaction; - await transactionRepository.updateTransaction(updatedTx); - } - // TODO: this is very specific to the crosschain-transfer. we should make it more generic - const continuationTx = composePactCommand( - continuation({ - pactId: contResult.continuation!.pactId, - step: contResult.continuation!.step + 1, - proof, - rollback: false, - data: {}, - }), - setMeta({ - chainId: crossChainId || request.chainId, - senderAccount: 'kadena-xchain-gas', - gasLimit: 850, - }), - setNetworkId(request.networkId), - )(); - const contTx = await transactionService.addTransaction({ - transaction: createTransaction(continuationTx), - networkUUID: tx.networkUUID, - profileId: updatedTx.profileId, - groupId: `${updatedTx.groupId}:continuation`, - }); - updatedTx = { - ...updatedTx, - continuation: { - ...continuationData, - continuationTxId: contTx.uuid, - }, - }; - await transactionRepository.updateTransaction(updatedTx); - // onUpdate(); - await onSubmit(contTx); - updatedTx = { - ...updatedTx, - continuation: { - ...updatedTx.continuation!, - done: true, - }, - }; - await transactionRepository.updateTransaction(updatedTx); - onUpdate(); - } - } - return updatedTx; - }; - - const onSendAll = async () => { - const result = await Promise.all(txs.map(onSubmit)); - if (onDone) { - onDone(); - } - console.log(result); - }; + await updatedTxs.map(transactionRepository.updateTransaction); + setTransactions(updatedTxs); + }; - const selectedTx = - selectedTxIndex !== undefined ? txs[selectedTxIndex] : undefined; + const onSendAll = async () => { + const onSubmit = async (tx: ITransaction) => { + return transactionService.onSubmitTransaction(tx, client, updateTx); + }; - const onExpandedSign = - (tx: ITransaction) => async (sigs: ITransaction['sigs']) => { - const updated = { - ...tx, - sigs, - status: sigs.every((data) => data?.sig) - ? steps.indexOf(tx.status) < steps.indexOf('signed') - ? 'signed' - : tx.status - : tx.status, - } as ITransaction; - await transactionRepository.updateTransaction(updated); - onUpdate(); + const txs = await Promise.all( + txIds.map(transactionRepository.getTransaction), + ); + const result = await Promise.all(txs.map(onSubmit)); + if (onDone) { + onDone(); + } + console.log(result); }; - return ( - - - {txs.length === 0 && No transactions} - {!showExpanded && - txs.map((tx, index) => ( - setSelectedTxIndex(index)} - onSubmit={() => onSubmit(tx)} - onSign={() => onSign(tx)} - sendDisabled={sendDisabled} - /> - ))} - {showExpanded && - txs.map((tx) => ( - - + + {transactions.length === 0 && No transactions} + {!showExpanded && + transactions.map((tx) => ( + onSubmit(tx)} sendDisabled={sendDisabled} + onUpdate={updateTx} /> + ))} + {showExpanded && + transactions.map((tx) => ( + + + + ))} + + {!showExpanded && + !transactions.every((tx) => statusPassed(tx.status, 'signed')) && ( + + You can sign all transactions at once. + + + - ))} - { - if (!isOpen) { - setSelectedTxIndex(undefined); - } - }} - > - {selectedTx && ( - onSubmit(selectedTx)} - sendDisabled={sendDisabled} - /> )} - - - {!showExpanded && - !txs.every((tx) => statusPassed(tx.status, 'signed')) && ( - - You can sign all transactions at once. - - - - - )} - {!showExpanded && - !sendDisabled && - txs.every((tx) => statusPassed(tx.status, 'signed')) && - txs.find((tx) => tx.status === 'signed') && ( - - - All transactions are signed. Now you can send them to the - blockchain - - - + {!showExpanded && + !sendDisabled && + transactions.every((tx) => statusPassed(tx.status, 'signed')) && + transactions.find((tx) => tx.status === 'signed') && ( + + + All transactions are signed. Now you can send them to the + blockchain + + + + - - )} - - ); -} + )} + + ); + }, + (prev, next) => { + if (prev.sendDisabled !== next.sendDisabled) return false; + if (prev.showExpanded !== next.showExpanded) return false; + if (prev.txIds.length !== next.txIds.length) return false; + return prev.txIds.every((txId, index) => txId === next.txIds[index]); + }, +); diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx new file mode 100644 index 0000000000..36d6b1ec76 --- /dev/null +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx @@ -0,0 +1,64 @@ +import { ITransaction } from '@/modules/transaction/transaction.repository'; + +import { MonoOpenInFull } from '@kadena/kode-icons/system'; +import { Button, Stack } from '@kadena/kode-ui'; + +import { useEffect, useRef } from 'react'; +import { TxPipeLine } from './TxPipeLine'; +import { txMinimizedClass } from './style.css'; + +export const TxMinimized = ({ + tx, + onSign, + onSubmit, + onView, + sendDisabled, + interactive = false, +}: { + tx: ITransaction; + onSign: () => void; + onSubmit: () => Promise; + onView: () => void; + sendDisabled?: boolean; + interactive?: boolean; +}) => { + const submittedRef = useRef(false); + useEffect(() => { + if (tx.status === 'signed' && !submittedRef.current) { + submittedRef.current = true; + onSubmit(); + } + }, [onSubmit, tx.status]); + return ( + + + + {interactive && tx.status === 'initiated' && ( + + )} + {interactive && tx.status === 'signed' && ( + + )} + + + + ); +}; diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxPipeLine.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxPipeLine.tsx index 7abab5b7b9..c5d570e49e 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/TxPipeLine.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxPipeLine.tsx @@ -46,22 +46,13 @@ export function TxPipeLine({ signAll, onSubmit, sendDisabled, -}: - | { - tx: ITransaction; - variant: 'tile'; - signAll?: () => Promise; - onSubmit?: () => Promise; - sendDisabled?: boolean; - } - | { - tx: ITransaction; - variant: 'expanded'; - signAll: () => Promise; - onSubmit: () => Promise; - sendDisabled?: boolean; - }) { - const textSize = variant === 'tile' ? 'smallest' : 'base'; +}: { + tx: ITransaction; + variant: 'tile' | 'expanded' | 'minimized'; + signAll?: () => void; + onSubmit?: () => void; + sendDisabled?: boolean; +}) { const [contTx] = useAsync( (transaction) => transaction.continuation?.continuationTxId @@ -74,55 +65,93 @@ export function TxPipeLine({ const showAfterCont = !contTx || variant === 'expanded'; return ( + + + ); +} + +function TxStatusList({ + variant, + showAfterCont, + tx, + signAll, + onSubmit, + sendDisabled, + contTx, +}: { + variant: 'tile' | 'expanded' | 'minimized'; + showAfterCont: boolean; + tx: ITransaction; + signAll?: () => void; + onSubmit?: () => void; + sendDisabled?: boolean; + contTx?: ITransaction | null; +}) { + const textSize = variant === 'tile' ? 'smallest' : 'base'; + const statusList = [ + variant !== 'minimized' && ( {tx.continuation?.autoContinue ? 'exec' : 'hash'}:{' '} {shorten(tx.hash, 6)} - {showAfterCont && - variant === 'expanded' && - !statusPassed(tx.status, 'signed') && ( - - - - - Waiting for sign - - + ), + showAfterCont && + variant !== 'tile' && + !statusPassed(tx.status, 'signed') && ( + + + + + Waiting for sign + + + {variant === 'expanded' && ( + )} + + ), + showAfterCont && statusPassed(tx.status, 'signed') && ( + + + + + Signed - )} - {showAfterCont && statusPassed(tx.status, 'signed') && ( - - + + + ), + showAfterCont && + variant !== 'tile' && + statusPassed(tx.status, 'signed') && + !statusPassed(tx.status, 'preflight') && ( + + - - Signed + + {sendDisabled ? 'Send is pending' : 'Ready to send'} - - )} - {showAfterCont && - variant === 'expanded' && - statusPassed(tx.status, 'signed') && - !statusPassed(tx.status, 'preflight') && ( - - - - - {sendDisabled ? 'Send is pending' : 'Ready to send'} - - - + {variant === 'expanded' && ( + )} + + ), + showAfterCont && statusPassed(tx.status, 'preflight') && ( + + + + {tx.preflight?.result.status === 'success' ? ( + + ) : ( + + )} + preflight + + + + ), + showAfterCont && statusPassed(tx.status, 'submitted') && ( + + + + + Send - )} - {showAfterCont && statusPassed(tx.status, 'preflight') && ( + + + ), + showAfterCont && + statusPassed(tx.status, 'submitted') && + (!('result' in tx) || !tx.result) && ( - + - {tx.preflight?.result.status === 'success' ? ( - - ) : ( - - )} - preflight + + Mining... - )} - {showAfterCont && statusPassed(tx.status, 'submitted') && ( + ), + statusPassed(tx.status, 'success') && ( + + + + + Mined{' '} + {tx.continuation?.autoContinue && contTx + ? `in chain ${tx.purpose!.data.source as string}` + : ''} + + + + ), + tx.status === 'failure' && ( + + + + + Failed + + + + ), + statusPassed(tx.status, 'success') && [ + tx.continuation?.autoContinue && !contTx && ( - + - - Send + + Fetching proof - )} - {showAfterCont && - statusPassed(tx.status, 'submitted') && - (!('result' in tx) || !tx.result) && ( - - - - - Mining... - - - - )} - {statusPassed(tx.status, 'success') && ( + ), + tx.continuation?.autoContinue && tx.continuation.proof && ( - Mined{' '} - {tx.continuation?.autoContinue && contTx - ? `in chain ${tx.purpose!.data.source as string}` - : ''} - - - - )} - {tx.status === 'failure' && ( - - - - - Failed + proof fetched - )} - {statusPassed(tx.status, 'success') && ( - <> - {tx.continuation?.autoContinue && !contTx && ( + ), + contTx && [ + variant !== 'minimized' && ( + + cont: {shorten(contTx.hash, 6)} + + + ), + statusPassed(contTx.status, 'preflight') && ( + + + + + preflight + + + + ), + statusPassed(contTx.status, 'submitted') && ( + + + + + Send + + + + ), + statusPassed(contTx.status, 'submitted') && + (!('result' in contTx) || !contTx.result) && ( - Fetching proof - - - - )} - {tx.continuation?.autoContinue && tx.continuation.proof && ( - - - - - proof fetched + Mining... - )} - {contTx && ( - <> - - cont: {shorten(contTx.hash, 6)} - + ), + statusPassed(contTx.status, 'success') && ( + + + + + Mined - {statusPassed(contTx.status, 'preflight') && ( - - - - - preflight - - - - )} - {statusPassed(contTx.status, 'submitted') && ( - - - - - Send - - - - )} - {statusPassed(contTx.status, 'submitted') && - (!('result' in contTx) || !contTx.result) && ( - - - - - Mining... - - - - )} - {statusPassed(contTx.status, 'success') && ( - - - - - Mined - - - - )} - {contTx.status === 'failure' && ( - - - - - Failed - - - - )} - - )} - - )} - - ); + + + ), + contTx.status === 'failure' && ( + + + + + Failed + + + + ), + ], + ], + ] + .flat(Infinity) + .filter(Boolean); + + if (variant === 'minimized') return statusList.pop() as JSX.Element; + return <>{statusList}; } diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/style.css.ts b/packages/apps/dev-wallet/src/pages/transaction/components/style.css.ts index 2a031205d8..ce6c89cf03 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/style.css.ts +++ b/packages/apps/dev-wallet/src/pages/transaction/components/style.css.ts @@ -113,3 +113,9 @@ export const txTileClass = style({ export const txTileContentClass = style({ flexBasis: 0, }); + +export const txMinimizedClass = style({ + padding: '3px', + paddingLeft: '5px', + border: `1px solid ${tokens.kda.foundation.color.border.base.default}`, +}); diff --git a/packages/apps/dev-wallet/src/pages/transfer-v2/Steps/Redistribution.tsx b/packages/apps/dev-wallet/src/pages/transfer-v2/Steps/Redistribution.tsx deleted file mode 100644 index 769b806f3a..0000000000 --- a/packages/apps/dev-wallet/src/pages/transfer-v2/Steps/Redistribution.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { Chain } from '@/Components/Badge/Badge'; -import { useWallet } from '@/modules/wallet/wallet.hook'; -import { Transaction } from '@/pages/transaction/Transaction'; -import { ISigner } from '@kadena/client'; -import { Box, Button, Notification, Stack } from '@kadena/kode-ui'; -import { useCallback, useState } from 'react'; -import { createRedistributionTxs } from '../utils'; -import { Redistribution, Transfer } from './TransferForm'; - -export function RedistributionPage({ - redistribution, - formData, -}: { - redistribution: Redistribution[]; - formData: Required; -}) { - const { fungibles, activeNetwork, getPublicKeyData } = useWallet(); - const [redistributionGroupId, setRedistributionGroupId] = useState(); - - const mapKeys = useCallback( - (key: ISigner) => { - if (typeof key === 'object') return key; - const info = getPublicKeyData(key); - if (info && info.scheme) { - return { - pubKey: key, - scheme: info.scheme, - }; - } - if (key.startsWith('WEBAUTHN')) { - return { - pubKey: key, - scheme: 'WebAuthn' as const, - }; - } - return key; - }, - [getPublicKeyData], - ); - - async function doRedistribution() { - if (redistribution.length > 0) { - if (!formData.senderAccount || !formData.senderAccount.keyset) return; - const [gid, txs] = await createRedistributionTxs({ - account: formData.senderAccount, - redistribution, - gasLimit: +formData.gasLimit, - gasPrice: +formData.gasPrice, - network: activeNetwork!, - mapKeys, - }); - if (txs.length > 0) { - setRedistributionGroupId(gid); - } - } - } - - return ( - - {redistributionGroupId ? ( - - ) : ( - - - Before proceeding with the transfer, the following redistribution - should happen: - {formData.senderAccount.address} - - {redistribution.map((r) => ( - - {'From '} - - {'to '} - - {r.amount}{' '} - {fungibles.find((ct) => ct.contract === formData.fungible) - ?.symbol ?? formData.fungible} - - ))} - - - - - - - )} - - ); -} diff --git a/packages/apps/dev-wallet/src/pages/transfer-v2/transfer-v2.tsx b/packages/apps/dev-wallet/src/pages/transfer-v2/transfer-v2.tsx index cba57d1580..7ac14ec331 100644 --- a/packages/apps/dev-wallet/src/pages/transfer-v2/transfer-v2.tsx +++ b/packages/apps/dev-wallet/src/pages/transfer-v2/transfer-v2.tsx @@ -199,11 +199,11 @@ export function TransferV2() { {onlyOneTx && ( { + onDone={() => { console.log('update'); reloadTxs(); }} - txs={txGroups.transfer.txs} + txIds={txGroups.transfer.txs.map(({ uuid }) => uuid)} showExpanded={true} /> )} @@ -215,11 +215,11 @@ export function TransferV2() { First we send required tokens to the target chains { + onDone={() => { console.log('update'); reloadTxs(); }} - txs={reTxs} + txIds={reTxs.map(({ uuid }) => uuid)} /> @@ -232,11 +232,11 @@ export function TransferV2() { These are the transactions for the final transfers { + onDone={() => { console.log('update'); reloadTxs(); }} - txs={txGroups.transfer.txs} + txIds={txGroups.transfer.txs.map(({ uuid }) => uuid)} sendDisabled={submitIsDisabled} /> {submitIsDisabled && (