Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

889: Consolidated balance handling in balances store #898

Merged
1 commit merged into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/components/Routes/Routes.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC } from "react";
import { Route, Switch } from "react-router-dom";

import useBalances from "../../features/balances/balancesHooks";
import { useTransactions } from "../../features/transactions/transactionsHooks";
import Cancel from "../../pages/Cancel/Cancel";
import MakePage from "../../pages/Make/Make";
Expand All @@ -10,6 +11,7 @@ import SwapPage from "../../pages/Swap/Swap";
import { AppRoutes } from "../../routes";

const Routes: FC = () => {
useBalances();
useTransactions();

return (
Expand Down
10 changes: 1 addition & 9 deletions src/components/TokenList/TokenList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ import { useWeb3React } from "@web3-react/core";

import { useAppDispatch } from "../../app/hooks";
import nativeCurrency from "../../constants/nativeCurrency";
import {
BalancesState,
requestActiveTokenAllowancesSwap,
requestActiveTokenAllowancesWrapper,
requestActiveTokenBalances,
} from "../../features/balances/balancesSlice";
import { BalancesState } from "../../features/balances/balancesSlice";
import {
addActiveToken,
addCustomToken,
Expand Down Expand Up @@ -164,9 +159,6 @@ const TokenList = ({
dispatch(addCustomToken(address));
}
await dispatch(addActiveToken(address));
dispatch(requestActiveTokenBalances({ provider: library }));
dispatch(requestActiveTokenAllowancesSwap({ provider: library }));
dispatch(requestActiveTokenAllowancesWrapper({ provider: library }));

onAfterAddActiveToken && onAfterAddActiveToken(address);
}
Expand Down
106 changes: 1 addition & 105 deletions src/features/balances/balancesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,13 @@ import erc20Abi from "erc-20-abi";
import { BigNumber, ethers, EventFilter, Event } from "ethers";
import { hexZeroPad, id } from "ethers/lib/utils";

interface SubscribeParams {
activeTokenAddresses: string[];
walletAddress: string;
spenderAddress: string;
provider: ethers.providers.Web3Provider;
onBalanceChange: (
tokenAddress: string,
amount: BigNumber,
direction: "in" | "out"
) => void;
onApproval: (
tokenAddress: string,
spenderAddress: string,
amount: BigNumber
) => void;
}

interface WalletParams {
chainId: number;
provider: ethers.providers.Web3Provider;
walletAddress: string;
tokenAddresses: string[];
}

const erc20Interface = new ethers.utils.Interface(erc20Abi);

/**
* Fetches balances or allowances for a wallet using the airswap utility
* contract `BalanceChecker.sol`. Balances are returned in base units.
Expand Down Expand Up @@ -71,89 +52,4 @@ const fetchAllowancesWrapper = fetchBalancesOrAllowances.bind(
"Wrapper"
);

// event Transfer(address indexed _from, address indexed _to, uint256 _value)
// event Approval(address indexed _owner, address indexed _spender, uint256 _value)
let subscribeToTransfersAndApprovals: (params: SubscribeParams) => () => void;
subscribeToTransfersAndApprovals = ({
activeTokenAddresses,
walletAddress,
provider,
onBalanceChange,
spenderAddress,
onApproval,
}) => {
// event Transfer(address indexed _from, address indexed _to, uint256 _value)
const filters: {
in: EventFilter;
out: EventFilter;
} = {
// Tokens being transferred out of our account or approved by our account
out: {
topics: [
[
id("Transfer(address,address,uint256)"),
id("Approval(address,address,uint256)"),
], // event name
hexZeroPad(walletAddress, 32), // from
],
},

// Tokens being transferred in to our account
in: {
topics: [
id("Transfer(address,address,uint256)"), // event name
[],
hexZeroPad(walletAddress, 32), // to
],
},
};

const tearDowns: (() => void)[] = [];

Object.keys(filters).forEach((direction) => {
// in or out?
const typedDirection = direction as keyof typeof filters;
const filter = filters[typedDirection];

function listener(event: Event) {
const { address } = event;
const lowerCasedTokenAddress = address.toLowerCase();

// Ignore transactions for non-active tokens.
if (!activeTokenAddresses.includes(lowerCasedTokenAddress)) return;

const parsedEvent = erc20Interface.parseLog(event);
const isApproval = parsedEvent.name === "Approval";

// Ignore approvals for other spenders.
const approvalAddress = parsedEvent.args[1].toLowerCase();
const wrapperAddress = (
Wrapper.getAddress(provider.network.chainId) || ""
).toLowerCase();
if (
isApproval &&
approvalAddress !== spenderAddress.toLowerCase() &&
approvalAddress !== wrapperAddress
)
return;

const amount: BigNumber = parsedEvent.args[2];
isApproval
? onApproval(lowerCasedTokenAddress, approvalAddress, amount)
: onBalanceChange(lowerCasedTokenAddress, amount, typedDirection);
}
provider.on(filter, listener);
tearDowns.push(provider.off.bind(provider, filter, listener));
});

return () => {
tearDowns.forEach((fn) => fn());
};
};

export {
fetchBalances,
fetchAllowancesSwap,
fetchAllowancesWrapper,
subscribeToTransfersAndApprovals,
};
export { fetchBalances, fetchAllowancesSwap, fetchAllowancesWrapper };
67 changes: 67 additions & 0 deletions src/features/balances/balancesHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useEffect, useState } from "react";

import { Web3Provider } from "@ethersproject/providers";
import { useWeb3React } from "@web3-react/core";

import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { TransactionTypes } from "../../types/transactionTypes";
import { fetchUnkownTokens } from "../metadata/metadataActions";
import { selectActiveTokens } from "../metadata/metadataSlice";
import useLatestSucceededTransaction from "../transactions/hooks/useLatestSucceededTransaction";
import {
requestActiveTokenAllowancesSwap,
requestActiveTokenAllowancesWrapper,
requestActiveTokenBalances,
} from "./balancesSlice";

export const useBalances = () => {
const { library, account, chainId } = useWeb3React<Web3Provider>();
const dispatch = useAppDispatch();

const activeTokens = useAppSelector(selectActiveTokens);
const latestSuccessfulTransaction = useLatestSucceededTransaction();

const [activeAccount, setActiveAccount] = useState<string>();
const [activeChainId, setActiveChainId] = useState<number>();

useEffect(() => {
if (!library || !activeTokens.length || !account) {
return;
}

if (activeAccount === account && activeChainId === chainId) {
return;
}

setActiveAccount(account);
setActiveChainId(chainId);

dispatch(requestActiveTokenBalances({ provider: library }));
dispatch(requestActiveTokenAllowancesSwap({ provider: library }));
dispatch(requestActiveTokenAllowancesWrapper({ provider: library }));
dispatch(fetchUnkownTokens({ provider: library }));
}, [account, chainId, library, activeTokens]);

useEffect(() => {
if (!latestSuccessfulTransaction || !library) {
return;
}

const { type } = latestSuccessfulTransaction;

if (
type === TransactionTypes.order ||
type === TransactionTypes.withdraw ||
type === TransactionTypes.deposit
) {
dispatch(requestActiveTokenBalances({ provider: library }));
}

if (type === TransactionTypes.approval) {
dispatch(requestActiveTokenAllowancesSwap({ provider: library }));
dispatch(requestActiveTokenAllowancesWrapper({ provider: library }));
}
}, [latestSuccessfulTransaction]);
};

export default useBalances;
16 changes: 0 additions & 16 deletions src/features/balances/balancesSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,22 +232,6 @@ export const allowancesWrapperSlice = getSlice(
requestActiveTokenAllowancesWrapper
);

export const {
incrementBy: incrementBalanceBy,
decrementBy: decrementBalanceBy,
set: setBalance,
} = balancesSlice.actions;
export const {
incrementBy: incrementAllowanceSwapBy,
decrementBy: decrementAllowanceSwapBy,
set: setAllowanceSwap,
} = allowancesSwapSlice.actions;
export const {
incrementBy: incrementAllowanceWrapperBy,
decrementBy: decreementAllowanceWrapperBy,
set: setAllowanceWrapper,
} = allowancesWrapperSlice.actions;

export const balancesActions = balancesSlice.actions;
export const allowancesSwapActions = allowancesSwapSlice.actions;
export const allowancesWrapperActions = allowancesWrapperSlice.actions;
Expand Down
58 changes: 3 additions & 55 deletions src/features/orders/ordersActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ import getWethAddress from "../../helpers/getWethAddress";
import toRoundedAtomicString from "../../helpers/toRoundedAtomicString";
import i18n from "../../i18n/i18n";
import { TransactionStatusType } from "../../types/transactionTypes";
import {
allowancesSwapActions,
decrementBalanceBy,
incrementBalanceBy,
} from "../balances/balancesSlice";
import {
declineTransaction,
revertTransaction,
Expand All @@ -69,8 +64,7 @@ import {

export const handleApproveTransaction = (
transaction: SubmittedApprovalTransaction,
status: TransactionStatusType,
dispatch: AppDispatch
status: TransactionStatusType
): void => {
if (status === TransactionStatusType.failed) {
notifyError({
Expand All @@ -81,25 +75,12 @@ export const handleApproveTransaction = (
return;
}

const amount = toRoundedAtomicString(
transaction.amount,
transaction.token.decimals
);

dispatch(
allowancesSwapActions.set({
tokenAddress: transaction.tokenAddress,
amount: amount,
})
);

notifyApproval(transaction);
};

export const handleSubmittedDepositOrder = (
transaction: SubmittedDepositTransaction,
status: TransactionStatusType,
dispatch: AppDispatch
status: TransactionStatusType
): void => {
if (status === TransactionStatusType.failed) {
notifyError({
Expand All @@ -110,29 +91,12 @@ export const handleSubmittedDepositOrder = (
return;
}

// TODO: Balance handling should be done in balancesApi.ts https://github.com/airswap/airswap-web/issues/889

dispatch(
incrementBalanceBy({
tokenAddress: transaction.signerToken.address,
amount: transaction.order.signerAmount,
})
);

dispatch(
decrementBalanceBy({
tokenAddress: transaction.senderToken.address,
amount: transaction.order.senderAmount,
})
);

notifyDeposit(transaction);
};

export const handleSubmittedWithdrawOrder = (
transaction: SubmittedWithdrawTransaction,
status: TransactionStatusType,
dispatch: AppDispatch
status: TransactionStatusType
): void => {
if (status === TransactionStatusType.failed) {
notifyError({
Expand All @@ -143,22 +107,6 @@ export const handleSubmittedWithdrawOrder = (
return;
}

// TODO: Balance handling should be done in balancesApi.ts https://github.com/airswap/airswap-web/issues/889

dispatch(
incrementBalanceBy({
tokenAddress: transaction.signerToken.address,
amount: transaction.order.signerAmount,
})
);

dispatch(
decrementBalanceBy({
tokenAddress: transaction.senderToken.address,
amount: transaction.order.senderAmount,
})
);

notifyWithdrawal(transaction);
};

Expand Down
9 changes: 4 additions & 5 deletions src/features/transactions/transactionsHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,17 @@ export const handleTransactionEvent =
};

export const handleTransactionResolved =
(transaction: SubmittedTransaction) =>
(dispatch: AppDispatch): void => {
(transaction: SubmittedTransaction) => (): void => {
if (isApprovalTransaction(transaction)) {
handleApproveTransaction(transaction, transaction.status, dispatch);
handleApproveTransaction(transaction, transaction.status);
}

if (isDepositTransaction(transaction)) {
handleSubmittedDepositOrder(transaction, transaction.status, dispatch);
handleSubmittedDepositOrder(transaction, transaction.status);
}

if (isWithdrawTransaction(transaction)) {
handleSubmittedWithdrawOrder(transaction, transaction.status, dispatch);
handleSubmittedWithdrawOrder(transaction, transaction.status);
}

if (isSubmittedOrder(transaction)) {
Expand Down
2 changes: 1 addition & 1 deletion src/features/transactions/transactionsHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const useTransactions = (): void => {
// If a transaction is successful, we want to handle it here.
useEffect(() => {
if (latestSuccessfulTransaction) {
dispatch(handleTransactionResolved(latestSuccessfulTransaction));
handleTransactionResolved(latestSuccessfulTransaction);
}
}, [latestSuccessfulTransaction]);
};
Loading
Loading