Skip to content

Commit

Permalink
feat: add multi-chain transaction history hooks (#1233)
Browse files Browse the repository at this point in the history
  • Loading branch information
brtkx authored Dec 4, 2023
1 parent 454978a commit 673446e
Show file tree
Hide file tree
Showing 44 changed files with 607 additions and 3,906 deletions.
49 changes: 2 additions & 47 deletions packages/arb-token-bridge-ui/src/components/App/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,14 @@ type AppContextState = {
isTransferPanelVisible: boolean
isTransferring: boolean
isTransactionHistoryPanelVisible: boolean
isTransactionHistoryShowingCctpDeposits: boolean
transactionHistorySelectedTab: TransactionHistoryTab
}
}

const initialState: AppContextState = {
layout: {
isTransferPanelVisible: true,
isTransferring: false,
isTransactionHistoryPanelVisible: false,
isTransactionHistoryShowingCctpDeposits: true,
transactionHistorySelectedTab: TransactionHistoryTab.DEPOSITS
isTransactionHistoryPanelVisible: false
}
}

Expand All @@ -40,8 +36,6 @@ type Action =
| { type: 'layout.set_is_transfer_panel_visible'; payload: boolean }
| { type: 'layout.set_is_transferring'; payload: boolean }
| { type: 'layout.set_txhistory_panel_visible'; payload: boolean }
| { type: 'layout.set_txhistory_show_cctp_deposits'; payload: boolean }
| { type: 'layout.set_txhistory_tab'; payload: TransactionHistoryTab }

function reducer(state: AppContextState, action: Action) {
switch (action.type) {
Expand All @@ -60,30 +54,12 @@ function reducer(state: AppContextState, action: Action) {
}
}

case 'layout.set_txhistory_show_cctp_deposits':
return {
...state,
layout: {
...state.layout,
isTransactionHistoryShowingCctpDeposits: action.payload
}
}

case 'layout.set_is_transferring':
return {
...state,
layout: { ...state.layout, isTransferring: action.payload }
}

case 'layout.set_txhistory_tab':
return {
...state,
layout: {
...state.layout,
transactionHistorySelectedTab: action.payload
}
}

default:
return state
}
Expand Down Expand Up @@ -122,34 +98,13 @@ export const useAppContextActions = (dispatchOverride?: Dispatch<Action>) => {
dispatch({ type: 'layout.set_txhistory_panel_visible', payload: true })
}

const showCctpDepositsTransactions = useCallback(() => {
dispatch({ type: 'layout.set_txhistory_show_cctp_deposits', payload: true })
}, [dispatch])

const showCctpWithdrawalsTransactions = useCallback(() => {
dispatch({
type: 'layout.set_txhistory_show_cctp_deposits',
payload: false
})
}, [dispatch])

const closeTransactionHistoryPanel = () => {
dispatch({ type: 'layout.set_txhistory_panel_visible', payload: false })
}

const setTransactionHistoryTab = useCallback(
(payload: TransactionHistoryTab) => {
dispatch({ type: 'layout.set_txhistory_tab', payload })
},
[dispatch]
)

return {
setTransferring,
openTransactionHistoryPanel,
closeTransactionHistoryPanel,
showCctpDepositsTransactions,
showCctpWithdrawalsTransactions,
setTransactionHistoryTab
closeTransactionHistoryPanel
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import { useEffect, useMemo, useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import useLocalStorage from '@rehooks/local-storage'

import { TransferPanel } from '../TransferPanel/TransferPanel'
import { TransactionHistory } from '../TransactionHistory/TransactionHistory'
import { SidePanel } from '../common/SidePanel'
import { useAppContextActions, useAppContextState } from '../App/AppContext'
import { useAppState } from '../../state'
import { useDeposits } from '../../hooks/useDeposits'
import { PageParams } from '../TransactionHistory/TransactionsTable/TransactionsTable'
import { useWithdrawals } from '../../hooks/useWithdrawals'
import { useNetworksAndSigners } from '../../hooks/useNetworksAndSigners'
import { TransactionStatusInfo } from '../TransactionHistory/TransactionStatusInfo'
import { ArbitrumStats, statsLocalStorageKey } from './ArbitrumStats'
import { SettingsDialog } from '../common/SettingsDialog'
import { isNetwork } from '../../util/networks'
import { NewTransactionHistory } from '../NewTransactionHistory/NewTransactionHistory'

export const motionDivProps = {
layout: true,
Expand All @@ -41,70 +33,11 @@ export function MainContent() {
const [isArbitrumStatsVisible] =
useLocalStorage<boolean>(statsLocalStorageKey)

const {
app: { arbTokenBridge }
} = useAppState()

const { l2 } = useNetworksAndSigners()

const [depositsPageParams, setDepositsPageParams] = useState<PageParams>({
searchString: '',
pageNumber: 0,
pageSize: 10
})

const [withdrawalsPageParams, setWithdrawalsPageParams] =
useState<PageParams>({
searchString: '',
pageNumber: 0,
pageSize: 10
})

const pageSize = useMemo(
() => (isNetwork(l2.network.id).isOrbitChain ? 5 : 10),
[l2.network.id]
)

const {
data: depositsData = {
deposits: [],
pendingDeposits: [],
transformedDeposits: []
},
isValidating: depositsLoading,
error: depositsError
} = useDeposits({ ...depositsPageParams, pageSize })

const {
data: withdrawalsData = {
withdrawals: [],
pendingWithdrawals: [],
transformedWithdrawals: []
},
isValidating: withdrawalsLoading,
error: withdrawalsError
} = useWithdrawals({ ...withdrawalsPageParams, pageSize })

useEffect(() => {
// if pending deposits found, add them in the store - this will add them to pending div + start polling for their status
arbTokenBridge?.transactions?.setDepositsInStore?.(
depositsData.pendingDeposits
)
}, [JSON.stringify(depositsData.pendingDeposits)]) // only run side effect on value change, not reference (Call stack exceeded)

useEffect(() => {
// if pending withdrawals found, add them in the store - this will add them to pending div + start polling for their status
arbTokenBridge?.setWithdrawalsInStore?.(withdrawalsData.pendingWithdrawals)
}, [JSON.stringify(withdrawalsData.pendingWithdrawals)]) // only run side effect on value change, not reference (Call stack exceeded)

return (
<div className="flex w-full justify-center">
<div className="main-panel w-full max-w-screen-lg flex-col space-y-6">
<div className="hidden text-center text-5xl">Arbitrum Token Bridge</div>

{/* if the user has some pending claim txns or retryables to redeem, show that banner here */}
<TransactionStatusInfo deposits={depositsData.transformedDeposits} />

<AnimatePresence>
<motion.div
key="transfer-panel"
Expand All @@ -120,21 +53,7 @@ export function MainContent() {
heading="Transaction History"
onClose={closeTransactionHistoryPanel}
>
{/* Transaction history - pending transactions + history table */}
<TransactionHistory
{...{
depositsPageParams: { ...depositsPageParams, pageSize },
withdrawalsPageParams: { ...withdrawalsPageParams, pageSize },
depositsData,
depositsLoading,
depositsError,
withdrawalsData,
withdrawalsLoading,
withdrawalsError,
setDepositsPageParams,
setWithdrawalsPageParams
}}
/>
<NewTransactionHistory />
</SidePanel>

{/* Settings panel */}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// DO NOT REVIEW, THIS WILL CHANGE A LOT WITH THE UI PR
// IT IS ONLY FOR TESTING

import { useAccount } from 'wagmi'
import dayjs from 'dayjs'

import { useTransactionHistory } from '../../hooks/useTransactionHistory'
import { DepositStatus, MergedTransaction } from '../../state/app/state'
import { getNetworkName } from '../../util/networks'
import { sanitizeTokenSymbol } from '../../util/TokenUtils'
import { getWagmiChain } from '../../util/wagmi/getWagmiChain'

function isDeposit(tx: MergedTransaction) {
return !tx.isWithdrawal
}

function getSourceChainId(tx: MergedTransaction) {
return isDeposit(tx) ? tx.parentChainId : tx.childChainId
}

function getDestChainId(tx: MergedTransaction) {
return isDeposit(tx) ? tx.childChainId : tx.parentChainId
}

function getTxStatus(tx: MergedTransaction) {
if (isDeposit(tx)) {
switch (tx.depositStatus) {
case DepositStatus.CREATION_FAILED:
case DepositStatus.L1_FAILURE:
case DepositStatus.L2_FAILURE:
return 'Failure'
case DepositStatus.EXPIRED:
return 'Expired'
case DepositStatus.L1_PENDING:
case DepositStatus.L2_PENDING:
return 'Pending'
default:
return 'Success'
}
} else {
switch (tx.status) {
case 'Executed':
return 'Success'
case 'Confirmed':
return 'Claimable'
case 'Unconfirmed':
return 'Pending'
default:
return 'Failure'
}
}
}

function getRelativeTime(tx: MergedTransaction) {
return dayjs(Number(tx.createdAt)).fromNow()
}

export const NewTransactionHistory = () => {
const { address } = useAccount()

const {
data: { transactions, total },
loading,
paused
} = useTransactionHistory(address)

if (loading || transactions.length === 0) {
return <div className="text-white">Fetching transactions...</div>
}

return (
<div className="text-white">
{typeof total === 'number' && transactions.length > 0 && (
<p>
Showing {transactions.length} out of {total} transactions
</p>
)}
<table className="w-full">
<thead>
<th>TIME</th>
<th>TOKEN</th>
<th>FROM</th>
<th>TO</th>
<th>STATUS</th>
<th />
</thead>
<tbody>
{transactions.map(tx => (
<tr key={`${tx.parentChainId}-${tx.childChainId}-${tx.txId}`}>
<td>{getRelativeTime(tx)}</td>
<td>
{tx.value}{' '}
{sanitizeTokenSymbol(tx.asset, {
erc20L1Address: tx.tokenAddress,
chain: getWagmiChain(tx.parentChainId)
})}
</td>
<td>{getNetworkName(getSourceChainId(tx))}</td>
<td>{getNetworkName(getDestChainId(tx))}</td>
<td>{getTxStatus(tx)}</td>
</tr>
))}
</tbody>
</table>
</div>
)
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit 673446e

Please sign in to comment.