diff --git a/packages/website/src/features/Deploy/QueueFromGitOpsPage.tsx b/packages/website/src/features/Deploy/QueueFromGitOpsPage.tsx index 51e4910ad..0b1f7548f 100644 --- a/packages/website/src/features/Deploy/QueueFromGitOpsPage.tsx +++ b/packages/website/src/features/Deploy/QueueFromGitOpsPage.tsx @@ -435,7 +435,8 @@ export default function QueueFromGitOps() { const execTxn = useWriteContract(); const isOutsideSafeTxnsRequired = - (buildState.result?.deployerSteps.length || 0) > 0 && !deployer.isComplete; + (buildState.result?.deployerSteps.length || 0) > 0 && + deployer.executionProgress.status !== 'success'; const loadingDataForDeploy = prevCannonDeployInfo.isFetching || @@ -930,7 +931,7 @@ export default function QueueFromGitOps() { p="4" borderRadius="md" > - {deployer.queuedTransactions.length === 0 ? ( + {buildState.result?.deployerSteps.length === 0 ? ( The following steps should be executed outside the safe @@ -957,11 +958,13 @@ export default function QueueFromGitOps() { Execute Outside Safe Txns - ) : deployer.executionProgress.length < - deployer.queuedTransactions.length ? ( + ) : deployer.executionProgress.status === 'executing' ? ( - Deploying txns {deployer.executionProgress.length + 1} /{' '} - {deployer.queuedTransactions.length} + Deploying txns{' '} + {deployer.transactionStatuses.findIndex( + (t) => t === 'executing' + ) + 1}{' '} + / {deployer.transactionStatuses.length} ) : ( diff --git a/packages/website/src/hooks/deployer.ts b/packages/website/src/hooks/deployer.ts index 41adee2a1..a033c11ce 100644 --- a/packages/website/src/hooks/deployer.ts +++ b/packages/website/src/hooks/deployer.ts @@ -1,77 +1,81 @@ -import { useAccount, useSendTransaction, useWaitForTransactionReceipt, useSwitchChain } from 'wagmi'; -import _ from 'lodash'; +import { useAccount, useSendTransaction, useSwitchChain } from 'wagmi'; import * as viem from 'viem'; -import { useState, useEffect } from 'react'; +import { useState } from 'react'; + +type Status = 'idle' | 'executing' | 'success' | 'error'; export function useDeployerWallet(chainId?: number) { - // for now, we just return the currently connected wallet const connectedAccount = useAccount(); - const [queuedTransactions, setQueuedTransactions] = useState([]); - const [executionProgress, setExecutionProgress] = useState([]); - const [error, setError] = useState(null); + const [transactionStatuses, setTransactionStatuses] = useState([]); + const [executionProgress, setExecutionProgress] = useState<{ + status: Status; + message?: string; + }>({ status: 'idle' }); const { switchChainAsync } = useSwitchChain(); + const { sendTransaction } = useSendTransaction(); - const { sendTransaction, isIdle, data: hash, error: txnError } = useSendTransaction(); + async function queueTransactions(txns: viem.TransactionRequestBase[]) { + setTransactionStatuses(Array(txns.length).fill('idle')); + setExecutionProgress({ status: 'executing' }); - const { isSuccess: isConfirmed } = useWaitForTransactionReceipt({ hash }); + if (!chainId) return; - useEffect( - function () { - if (!chainId) { - return; - } + try { + for (let i = 0; i < txns.length; i++) { + await switchChainAsync({ chainId }); - (async () => { - // is this the first transaction, or have we finished executing a transaction? - if ((isIdle && !executionProgress.length && queuedTransactions.length) || isConfirmed) { - // ensure we are on the correct network - await switchChainAsync({ chainId }); - // execute the next transaction - sendTransaction( - { - ...queuedTransactions[executionProgress.length], - type: queuedTransactions[executionProgress.length].type as - | 'legacy' - | 'eip2930' - | 'eip1559' - | 'eip4844' - | 'eip7702' - | undefined, - }, - { - onSuccess(hash: viem.Hash) { - setExecutionProgress([...executionProgress, hash]); - }, - } - ); - } - })() - .then(_.noop) - .catch((err) => { - // unexpected issue in the deployer - // eslint-disable-next-line no-console - console.error('deployer issue', err); - setError(err); + setTransactionStatuses((prevStatuses) => { + const newStatuses = [...prevStatuses]; + newStatuses[i] = 'executing'; + return newStatuses; }); - }, - [isConfirmed, isIdle, executionProgress.length, queuedTransactions, chainId] - ); + + sendTransaction( + { + ...txns[i], + type: txns[i].type as 'legacy' | 'eip2930' | 'eip1559' | 'eip4844' | 'eip7702' | undefined, + }, + { + onSuccess: () => { + setTransactionStatuses((prevStatuses) => { + const newStatuses = [...prevStatuses]; + newStatuses[i] = 'success'; + return newStatuses; + }); + + const isLastTransaction = i === txns.length - 1; + if (isLastTransaction) { + setExecutionProgress({ status: 'success' }); + } + }, + onError: (error) => { + setTransactionStatuses((prevStatuses) => { + const newStatuses = [...prevStatuses]; + newStatuses[i] = 'error'; + return newStatuses; + }); + setExecutionProgress({ status: 'error', message: error.message }); + throw error; + }, + } + ); + } + } catch (err) { + setExecutionProgress({ status: 'error', message: (err as Error).message }); + } + } return { address: connectedAccount.address, - queuedTransactions, + transactionStatuses, executionProgress, - isComplete: queuedTransactions.length > 0 && executionProgress.length === queuedTransactions.length, - error: error || txnError, - queueTransactions: function (txn: viem.TransactionRequestBase[]) { - setQueuedTransactions([...queuedTransactions, ...txn]); - }, + queueTransactions, reset: function () { - setQueuedTransactions([]); - setExecutionProgress([]); + setTransactionStatuses([]); + setExecutionProgress({ status: 'idle' }); }, }; }