Skip to content

Commit

Permalink
888: Refactor of useHistoricalTransactions
Browse files Browse the repository at this point in the history
  • Loading branch information
piersss committed Mar 29, 2024
1 parent efd735d commit efab39c
Show file tree
Hide file tree
Showing 19 changed files with 424 additions and 443 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"dependencies": {
"@airswap/libraries": "4.3.4",
"@airswap/pool": "^4.2.2",
"@craco/craco": "^6.2.0",
"@fontsource/dm-mono": "^4.5.0",
"@greypixel_/nicenumbers": "^0.0.18",
Expand Down
5 changes: 2 additions & 3 deletions src/components/Page/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { useAppDispatch } from "../../app/hooks";
import { WalletProvider } from "../../constants/supportedWalletProviders";
import { InterfaceContext } from "../../contexts/interface/Interface";
import { clear, setResetStatus } from "../../features/orders/ordersSlice";
import useHistoricalTransactions from "../../features/transactions/hooks/useHistoricalTransactions";
import useTransactionsFilterFromLocalStorage from "../../features/transactions/hooks/useTransactionsFilterFromLocalStorage";
import { useTransactions } from "../../features/transactions/transactionsHooks";
import useHistoricalTransactions from "../../features/transactions/useHistoricalTransactions";
import useTransactionsFilterFromLocalStorage from "../../features/transactions/useTransactionsFilterFromLocalStorage";
import { Wallet } from "../../features/wallet/Wallet";
import { setActiveProvider } from "../../features/wallet/walletSlice";
import useAppRouteParams from "../../hooks/useAppRouteParams";
Expand Down Expand Up @@ -46,7 +46,6 @@ const Page: FC<PageProps> = ({ children, className }): ReactElement => {
} = useContext(InterfaceContext);

useTransactions();
// useHistoricalTransactions();
useTransactionsFilterFromLocalStorage();

useKeyPress(() => setShowMobileToolbar(false), ["Escape"]);
Expand Down
2 changes: 1 addition & 1 deletion src/components/TransactionsTab/TransactionsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const TransactionsTab = ({
</LegendContainer>
<TransactionContainer>
<AnimatePresence initial={false}>
{completedTransactions.slice(0, 10).map((transaction) => (
{completedTransactions.map((transaction) => (
<AnimatedWalletTransaction
key={`${transaction.hash}-${transaction.nonce}-${transaction.expiry}`}
transaction={transaction}
Expand Down
1 change: 1 addition & 0 deletions src/contexts/lastLook/LastLook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ const LastLookProvider: FC = ({ children }) => {
const senderToken = tokens.find((t) => t.address === order.senderToken);

const transaction = transformToSubmittedLastLookOrder(
undefined,
order,
signerToken!,
senderToken!
Expand Down
19 changes: 19 additions & 0 deletions src/entities/OrderERC20/OrderERC20Transformers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { OrderERC20, Signature } from "@airswap/utils";
import { FullSwapERC20 } from "@airswap/utils/build/src/swap-erc20";

export const transformFullSwapERC20ToOrderERC20 = (
swap: FullSwapERC20,
nonce: string,
signature: Signature = { v: "", r: "", s: "" }
): OrderERC20 => {
return {
nonce,
expiry: Math.round(+nonce / 1000).toString(),
signerWallet: swap.signerWallet,
signerToken: swap.signerToken,
signerAmount: swap.signerAmount,
senderToken: swap.senderToken,
senderAmount: swap.senderAmount,
...signature,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,10 @@ export const isOrderTransaction = (
isLastLookOrderTransaction(transaction)
);
};

export const sortSubmittedTransactionsByExpiry = (
a: SubmittedTransaction,
b: SubmittedTransaction
) => {
return b.timestamp - a.timestamp;
};
Original file line number Diff line number Diff line change
Expand Up @@ -79,37 +79,41 @@ export const transformToSubmittedRFQOrder = (
order: OrderERC20,
signerToken: TokenInfo,
senderToken: TokenInfo,
status: StatusType = "processing"
status: StatusType = "processing",
timestamp = Date.now()
): SubmittedRFQOrder => {
return {
type: "Order",
expiry: order.expiry,
hash: hash,
hash,
nonce: order.nonce,
order,
protocol: "request-for-quote-erc20",
senderToken,
signerToken,
status,
timestamp: Date.now(),
timestamp,
};
};

export const transformToSubmittedLastLookOrder = (
hash: string | undefined,
order: OrderERC20,
signerToken: TokenInfo,
senderToken: TokenInfo,
status: StatusType = "processing"
status: StatusType = "processing",
timestamp = Date.now()
): SubmittedLastLookOrder => {
return {
type: "Order",
expiry: order.expiry,
hash,
nonce: order.nonce,
order,
protocol: "last-look-erc20",
senderToken,
signerToken,
status,
timestamp: Date.now(),
timestamp,
};
};
104 changes: 104 additions & 0 deletions src/features/transactions/hooks/useHistoricalTransactions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { useMemo, useState } from "react";

import { useAppSelector } from "../../../app/hooks";
import { SubmittedTransaction } from "../../../entities/SubmittedTransaction/SubmittedTransaction";
import { sortSubmittedTransactionsByExpiry } from "../../../entities/SubmittedTransaction/SubmittedTransactionHelpers";
import { transformToSubmittedRFQOrder } from "../../../entities/SubmittedTransaction/SubmittedTransactionTransformers";
import { getUniqueArrayChildren } from "../../../helpers/array";
import { getOrdersFromLogs } from "../../../helpers/getOrdersFromLogs";
import { selectAllTokenInfo } from "../../metadata/metadataSlice";
import useSwapLogs from "./useSwapLogs";

interface HistoricalTransactionsCollection {
chainId: number;
account: string;
transactions: SubmittedTransaction[];
}

const useHistoricalTransactions = (
chainId?: number,
account?: string
): [HistoricalTransactionsCollection | undefined, boolean] => {
const tokens = useAppSelector(selectAllTokenInfo);
const { result: swapLogs, status: swapLogStatus } = useSwapLogs(
chainId,
account
);

const [isLoading, setIsLoading] = useState(false);
const [transactions, setTransactions] =
useState<HistoricalTransactionsCollection>();

useMemo(() => {
if (
!chainId ||
!swapLogs ||
swapLogStatus === "loading" ||
swapLogStatus === "not-executed" ||
swapLogs.chainId !== chainId ||
swapLogs.account !== account
) {
return;
}

setIsLoading(true);
setTransactions(undefined);

const getTransactionsFromLogs = async () => {
const rfqOrders = await getOrdersFromLogs(chainId, swapLogs.swapLogs);
// TODO: Add support for lastLook orders https://github.com/airswap/airswap-web/issues/891
// const lastLookOrders = await getOrdersFromLogs(swapLogs.swapLogs);

const rfqSubmittedTransactions = rfqOrders
.filter(
(order) =>
order.params.signerWallet.toLowerCase() === account.toLowerCase() ||
order.senderWallet.toLowerCase() === account.toLowerCase()
)
.map((order) => {
const signerToken = tokens.find(
(token) => token.address === order.params.signerToken
);
const senderToken = tokens.find(
(token) => token.address === order.params.senderToken
);

if (!signerToken || !senderToken) return;

return transformToSubmittedRFQOrder(
order.hash,
order.params,
signerToken,
senderToken,
"succeeded",
order.timestamp
);
});

const transactions = rfqSubmittedTransactions.filter(
(order) => !!order
) as SubmittedTransaction[];
const uniqueTransactions = getUniqueArrayChildren<SubmittedTransaction>(
transactions,
"nonce"
);

const sortedTransactions = uniqueTransactions.sort(
sortSubmittedTransactionsByExpiry
);

setIsLoading(false);
setTransactions({
chainId,
account,
transactions: sortedTransactions,
});
};

getTransactionsFromLogs();
}, [swapLogs, swapLogStatus]);

return [transactions, isLoading];
};

export default useHistoricalTransactions;
92 changes: 92 additions & 0 deletions src/features/transactions/hooks/useSwapLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { useEffect, useState } from "react";

import { SwapERC20, Wrapper } from "@airswap/libraries";
import { Contract } from "@ethersproject/contracts";
import { useAsync } from "@react-hookz/web/esm";
import { IAsyncState } from "@react-hookz/web/esm/useAsync/useAsync";
import { useWeb3React } from "@web3-react/core";

import { Event } from "ethers";
import { providers } from "ethers";

import getContractEvents from "../../../helpers/getContractEvents";

interface SwapLogs {
swapLogs: Event[];
wrappedSwapLogs: Event[];
chainId: number;
account: string;
}

const useSwapLogs = (
chainId?: number,
account?: string
): IAsyncState<SwapLogs | null> => {
const { library: provider } = useWeb3React<providers.Provider>();

const [accountState, setAccountState] = useState<string>();
const [chainIdState, setChainIdState] = useState<number>();

const [state, actions] = useAsync(
async (
swapContract: Contract,
wrapperContract: Contract,
account: string
) => {
const signerSwapFilter = swapContract.filters.SwapERC20(null);
const wrapperSwapFilter = wrapperContract.filters.WrappedSwapFor(null);

const firstTxBlockSwapContract =
chainId && SwapERC20.deployedBlocks[chainId];
const firstTxBlockWrapperContract =
chainId && Wrapper.deployedBlocks[chainId];
const currentBlock = await provider?.getBlockNumber();

if (
!firstTxBlockSwapContract ||
!firstTxBlockWrapperContract ||
!currentBlock
) {
throw new Error("Could not get block numbers");
}

const swapLogs = await getContractEvents(
swapContract,
signerSwapFilter,
firstTxBlockSwapContract,
currentBlock
);
const wrappedSwapLogs = await getContractEvents(
wrapperContract,
wrapperSwapFilter,
firstTxBlockWrapperContract,
currentBlock
);

return {
swapLogs,
wrappedSwapLogs,
chainId,
account,
};
},
null
);

useEffect(() => {
if (!chainId || !account || !provider) return;

if (account === accountState && chainId === chainIdState) return;

const swapContract = SwapERC20.getContract(provider, chainId);
const wrapperContract = Wrapper.getContract(provider, chainId);
actions.execute(swapContract, wrapperContract, account);

setAccountState(account);
setChainIdState(chainId);
}, [chainId, account, provider, actions]);

return state;
};

export default useSwapLogs;
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { useEffect } from "react";
import { useLocalStorageValue } from "@react-hookz/web/esm";
import { useWeb3React } from "@web3-react/core";

import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { useAppDispatch, useAppSelector } from "../../../app/hooks";
import {
selectTransactionsFilter,
setFilters,
TransactionsState,
} from "./transactionsSlice";
import { getTransactionsFilterLocalStorageKey } from "./transactionsUtils";
} from "../transactionsSlice";
import { getTransactionsFilterLocalStorageKey } from "../transactionsUtils";

const useTransactionsFilterFromLocalStorage = () => {
const dispatch = useAppDispatch();
Expand Down
35 changes: 34 additions & 1 deletion src/features/transactions/transactionsHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { useWeb3React } from "@web3-react/core";

import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { SubmittedTransaction } from "../../entities/SubmittedTransaction/SubmittedTransaction";
import { sortSubmittedTransactionsByExpiry } from "../../entities/SubmittedTransaction/SubmittedTransactionHelpers";
import { getUniqueArrayChildren } from "../../helpers/array";
import useHistoricalTransactions from "./hooks/useHistoricalTransactions";
import { selectTransactions, setTransactions } from "./transactionsSlice";
import {
getLocalStorageTransactions,
Expand All @@ -14,13 +17,17 @@ import {
export const useTransactions = (): void => {
const dispatch = useAppDispatch();

const { account, library, chainId } = useWeb3React();
const { chainId, account, library } = useWeb3React();
const transactions: SubmittedTransaction[] =
useAppSelector(selectTransactions);

const [activeListenerHashes, setActiveListenerHashes] = useState<string[]>(
[]
);
const [historicalTransactions] = useHistoricalTransactions(
chainId,
account || undefined
);

useEffect(() => {
if (!account || !chainId || !library) {
Expand Down Expand Up @@ -53,4 +60,30 @@ export const useTransactions = (): void => {

dispatch(setTransactions(getLocalStorageTransactions(account, chainId)));
}, [account, chainId]);

useEffect(() => {
if (!historicalTransactions) {
return;
}

if (
historicalTransactions.chainId === chainId &&
historicalTransactions.account === account
) {
const updatedTransactions = [
...historicalTransactions.transactions,
...transactions,
];
// Remove duplicates, in favour of store transactions.
const uniqueTransactions = getUniqueArrayChildren<SubmittedTransaction>(
updatedTransactions,
"hash"
);
const sortedTransactions = uniqueTransactions.sort(
sortSubmittedTransactionsByExpiry
);

dispatch(setTransactions(sortedTransactions));
}
}, [historicalTransactions]);
};
Loading

0 comments on commit efab39c

Please sign in to comment.