-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: transaction history data fetching * fix: jumpy bg image * feat: listing transaction history
- Loading branch information
1 parent
ffdfb82
commit d73bca7
Showing
10 changed files
with
270 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,7 @@ | |
] | ||
}, | ||
"dependencies": { | ||
"moment": "^2.30.1", | ||
"notistack": "^3.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import moment from 'moment'; | ||
import { Box, Link, Typography } from '@mui/material'; | ||
import { BridgeAction } from 'src/hooks/useTransactionHistory'; | ||
import { Direction } from 'src/context/AppContext'; | ||
import AeternityIcon from './icons/aeternity'; | ||
import EthereumIcon from './icons/ethereum'; | ||
import ArrowForwardIcon from '@mui/icons-material/ArrowForward'; | ||
import getTxUrl from 'src/utils/getTxUrl'; | ||
|
||
interface Props { | ||
item: BridgeAction; | ||
} | ||
|
||
const BridgeActionListItem = ({ item }: Props) => { | ||
const date = moment(item.timestamp); | ||
const fromNow = date.fromNow(); | ||
|
||
return ( | ||
<Box | ||
flex={1} | ||
flexDirection={'row'} | ||
display={'flex'} | ||
gap={2} | ||
justifyContent={'space-around'} | ||
flexWrap={'wrap'} | ||
mt={1} | ||
mb={1} | ||
pt={1} | ||
pb={1} | ||
sx={{ '&:nth-child(even)': { backgroundColor: 'rgba(0, 0, 0, 0.05)' } }} | ||
> | ||
<Typography sx={{ color: 'black' }} component={'span'} variant="body1" width={120}> | ||
<Link target="_blank" href={getTxUrl(item.direction, item.hash)}> | ||
{fromNow} | ||
</Link> | ||
</Typography> | ||
|
||
<Box display="flex" alignItems={'center'} gap={1}> | ||
{item.direction === Direction.AeternityToEthereum ? ( | ||
<> | ||
<AeternityIcon /> | ||
<Typography component="span" variant="body1"> | ||
æternity | ||
</Typography> | ||
<ArrowForwardIcon /> | ||
<EthereumIcon /> | ||
<Typography component="span" variant="body1"> | ||
Ethereum | ||
</Typography> | ||
</> | ||
) : ( | ||
<> | ||
<EthereumIcon /> | ||
<Typography component="span" variant="body1"> | ||
Ethereum | ||
</Typography> | ||
<ArrowForwardIcon /> | ||
<AeternityIcon /> | ||
<Typography component="span" variant="body1"> | ||
æternity | ||
</Typography> | ||
</> | ||
)} | ||
</Box> | ||
|
||
<Box display={'flex'} gap={1} alignItems={'center'} width={120}> | ||
<img width={28} height={28} src={item.tokenIcon} alt={item.tokenSymbol} /> | ||
<Typography component="span" variant="body1"> | ||
{item.amount} | ||
</Typography> | ||
<Typography component="span" variant="body1"> | ||
{item.tokenSymbol} | ||
</Typography> | ||
</Box> | ||
</Box> | ||
); | ||
}; | ||
export default BridgeActionListItem; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import { useEffect, useState } from 'react'; | ||
import { Direction } from 'src/context/AppContext'; | ||
import Constants from 'src/constants'; | ||
import * as Ethereum from 'src/services/ethereum'; | ||
import BigNumber from 'bignumber.js'; | ||
import { Event } from 'ethers'; | ||
|
||
export interface BridgeAction { | ||
direction: Direction; | ||
hash: string; | ||
toAddress: string; | ||
tokenSymbol: string; | ||
tokenIcon: string; | ||
amount: number; | ||
timestamp: number; | ||
} | ||
|
||
const useTransactionHistory = (direction: Direction, address?: string) => { | ||
const [transactions, setTransactions] = useState<BridgeAction[]>([]); | ||
const [loading, setLoading] = useState<boolean>(false); | ||
|
||
useEffect(() => { | ||
(async function () { | ||
setLoading(true); | ||
|
||
if (direction === Direction.AeternityToEthereum) { | ||
setTransactions(await fetchAeternityTransactions(address)); | ||
} else if (direction === Direction.EthereumToAeternity) { | ||
setTransactions(await fetchEthereumTransactions(address)); | ||
} | ||
|
||
setLoading(false); | ||
})(); | ||
}, [direction, address]); | ||
|
||
return { transactions, loading }; | ||
}; | ||
|
||
const fetchEthereumTransactions = async (address?: string) => { | ||
if (!address) { | ||
return []; | ||
} | ||
|
||
const bridgeContract = new Ethereum.Contract( | ||
Constants.ethereum.bridge_address, | ||
Constants.ethereum.bridge_abi, | ||
Ethereum.Provider, | ||
); | ||
const filter = bridgeContract.filters.BridgeOut(); | ||
const events = await bridgeContract.queryFilter(filter, 20141309, 'latest'); | ||
|
||
return await parseEthereumTransactions(events); | ||
}; | ||
|
||
const parseEthereumTransactions = async (events: any): Promise<BridgeAction[]> => { | ||
const actions = await Promise.all( | ||
events.map(async (event: Event) => { | ||
const token = Constants.assets.find( | ||
(asset) => asset.ethAddress.toLowerCase() === event.args![0].toLowerCase(), | ||
)!; | ||
const toAddress = event.args![2]; | ||
const amount = new BigNumber(event.args![3].toString()).toNumber(); | ||
|
||
const block = await event.getBlock(); | ||
return { | ||
amount: new BigNumber(amount).shiftedBy(-token.decimals).toNumber(), | ||
toAddress, | ||
tokenIcon: token.icon, | ||
tokenSymbol: token.symbol, | ||
hash: event.transactionHash, | ||
timestamp: block.timestamp * 1000, | ||
direction: Direction.EthereumToAeternity, | ||
}; | ||
}), | ||
); | ||
|
||
return actions.reverse(); | ||
}; | ||
|
||
const fetchAeternityTransactions = async (address?: string) => { | ||
if (!address) { | ||
return []; | ||
} | ||
|
||
const transactionsStartUrl = `${Constants.aeAPI}/v3/transactions?account=${address}&contract_id=${Constants.aeternity.bridge_address}&entrypoint=bridge_out&limit=100`; | ||
const fetchTransactions = async (url: string, prevData: any[] = []): Promise<any[]> => { | ||
const _response = await fetch(url); | ||
const response = await _response.json(); | ||
|
||
const aggregatedData = [...prevData, ...response.data]; | ||
if (response.next) { | ||
return fetchTransactions(`${Constants.aeAPI}${response.next}`, aggregatedData); | ||
} else { | ||
return aggregatedData; | ||
} | ||
}; | ||
|
||
const transactions = await fetchTransactions(transactionsStartUrl); | ||
|
||
return parseAeternityTransactions(transactions); | ||
}; | ||
|
||
const parseAeternityTransactions = (transactions: any): BridgeAction[] => { | ||
return transactions.map((transaction: any) => { | ||
const token = Constants.assets.find( | ||
(asset) => asset.ethAddress.toLowerCase() === transaction.tx.arguments[0].value[0].value.toLowerCase(), | ||
)!; | ||
const toAddress = transaction.tx.arguments[0].value[1].value; | ||
const amount = transaction.tx.arguments[0].value[2].value; | ||
|
||
return { | ||
amount: new BigNumber(amount).shiftedBy(-token.decimals).toNumber(), | ||
toAddress, | ||
tokenIcon: token.icon, | ||
tokenSymbol: token.symbol, | ||
hash: transaction.hash, | ||
timestamp: transaction.micro_time, | ||
direction: Direction.AeternityToEthereum, | ||
}; | ||
}); | ||
}; | ||
|
||
export default useTransactionHistory; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import Constants from 'src/constants'; | ||
import { Direction } from 'src/context/AppContext'; | ||
|
||
const getTxUrl = (direction: Direction, hash: string) => { | ||
return direction === Direction.AeternityToEthereum | ||
? `${Constants.aeternity.explorer}/transactions/${hash}` | ||
: `${Constants.ethereum.etherscan}/tx/${hash}`; | ||
}; | ||
|
||
export default getTxUrl; |
Oops, something went wrong.