Skip to content

Commit

Permalink
feat: update flow for handling transactions (#1617)
Browse files Browse the repository at this point in the history
  • Loading branch information
therealemjy authored Nov 7, 2023
1 parent f079cea commit f6420d5
Show file tree
Hide file tree
Showing 69 changed files with 1,070 additions and 1,050 deletions.
18 changes: 18 additions & 0 deletions src/__mocks__/models/contractTransaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BigNumber as BN, ContractTransaction } from 'ethers';
import { ChainId } from 'types';

const contractTransaction: ContractTransaction = {
hash: 'fake-transaction-hash',
type: 1,
wait: vi.fn(),
confirmations: 0,
from: '0x1d759121234cd36F8124C21aFe1c6852d2bEd848',
to: '0x2d759121234cd36F8124C21aFe1c6852d2bEd834',
nonce: 10,
gasLimit: BN.from('100000000000'),
data: 'Fake data',
value: BN.from('0'),
chainId: ChainId.BSC_TESTNET,
};

export default contractTransaction;
2 changes: 2 additions & 0 deletions src/__mocks__/models/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ export const balance = BigNumber.from('1000000000000000000');

const getBlockNumber = vi.fn(async () => blockNumber);
const getBalance = vi.fn(async () => balance);
const waitForTransaction = vi.fn(async () => {});

const provider = {
getBlockNumber,
getBalance,
waitForTransaction,
} as unknown as Provider;

export default provider;
4 changes: 0 additions & 4 deletions src/clients/api/__mocks__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ export const getVaiTreasuryPercentage = vi.fn();
export const useGetVaiTreasuryPercentage = () =>
useQuery(FunctionKey.GET_VAI_TREASURY_PERCENTAGE, getVaiTreasuryPercentage);

export const getMainAssetsInAccount = vi.fn();
export const useGetMainAssetsInAccount = () =>
useQuery(FunctionKey.GET_MAIN_ASSETS_IN_ACCOUNT, getMainAssetsInAccount);

export const getHypotheticalAccountLiquidity = vi.fn();

export const getMainMarkets = vi.fn();
Expand Down
4 changes: 0 additions & 4 deletions src/clients/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,6 @@ export { default as getVaiTreasuryPercentage } from './queries/getVaiTreasuryPer
export * from './queries/getVaiTreasuryPercentage';
export { default as useGetVaiTreasuryPercentage } from './queries/getVaiTreasuryPercentage/useGetVaiTreasuryPercentage';

export { default as getMainAssetsInAccount } from './queries/getMainAssetsInAccount';
export * from './queries/getMainAssetsInAccount';
export { default as useGetMainAssetsInAccount } from './queries/getMainAssetsInAccount/useGetMainAssetsInAccount';

export { default as getHypotheticalAccountLiquidity } from './queries/getHypotheticalAccountLiquidity';
export * from './queries/getHypotheticalAccountLiquidity';

Expand Down
13 changes: 4 additions & 9 deletions src/clients/api/mutations/approveToken/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { Bep20 } from 'packages/contracts';

import fakeAddress from '__mocks__/models/address';
import fakeContractReceipt from '__mocks__/models/contractReceipt';
import fakeContractTransaction from '__mocks__/models/contractTransaction';
import MAX_UINT256 from 'constants/maxUint256';

import approveToken from '.';

describe('api/mutations/approveToken', () => {
describe('approveToken', () => {
test('returns contract receipt when request succeeds', async () => {
const waitMock = vi.fn(async () => fakeContractReceipt);
const approveTokenMock = vi.fn(() => ({
wait: waitMock,
}));
const approveTokenMock = vi.fn(async () => fakeContractTransaction);

const fakeContract = {
approve: approveTokenMock,
Expand All @@ -23,10 +20,8 @@ describe('api/mutations/approveToken', () => {
allowance: MAX_UINT256.toFixed(),
});

expect(response).toBe(fakeContractReceipt);
expect(response).toBe(fakeContractTransaction);
expect(approveTokenMock).toHaveBeenCalledTimes(1);
expect(approveTokenMock).toHaveBeenCalledWith(fakeAddress, MAX_UINT256.toFixed());
expect(waitMock).toBeCalledTimes(1);
expect(waitMock).toHaveBeenCalledWith(1);
});
});
10 changes: 4 additions & 6 deletions src/clients/api/mutations/approveToken/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ContractReceipt } from 'ethers';
import { ContractTransaction } from 'ethers';
import { Bep20, Vai, Vrt, Xvs } from 'packages/contracts';

import MAX_UINT256 from 'constants/maxUint256';
Expand All @@ -9,15 +9,13 @@ export interface ApproveTokenInput {
allowance?: string;
}

export type ApproveTokenOutput = ContractReceipt;
export type ApproveTokenOutput = ContractTransaction;

const approveToken = async ({
tokenContract,
spenderAddress,
allowance = MAX_UINT256.toFixed(),
}: ApproveTokenInput): Promise<ApproveTokenOutput> => {
const transaction = await tokenContract.approve(spenderAddress, allowance);
return transaction.wait(1);
};
}: ApproveTokenInput): Promise<ApproveTokenOutput> =>
tokenContract.approve(spenderAddress, allowance);

export default approveToken;
43 changes: 18 additions & 25 deletions src/clients/api/mutations/approveToken/useApproveToken.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,40 @@
import { useGetTokenContract } from 'packages/contracts';
import { MutationObserverOptions, useMutation } from 'react-query';
import { Token } from 'types';
import { callOrThrow } from 'utilities';

import { ApproveTokenInput, ApproveTokenOutput, approveToken, queryClient } from 'clients/api';
import { ApproveTokenInput, approveToken, queryClient } from 'clients/api';
import FunctionKey from 'constants/functionKey';
import { UseSendTransactionOptions, useSendTransaction } from 'hooks/useSendTransaction';

type TrimmedApproveTokenInput = Omit<ApproveTokenInput, 'tokenContract'>;
type Options = MutationObserverOptions<ApproveTokenOutput, Error, TrimmedApproveTokenInput>;
type Options = UseSendTransactionOptions<TrimmedApproveTokenInput>;

const useApproveToken = ({ token }: { token: Token }, options?: Options) => {
const tokenContract = useGetTokenContract({ token, passSigner: true });

return useMutation(
[FunctionKey.APPROVE_TOKEN, { token }],
(input: TrimmedApproveTokenInput) =>
return useSendTransaction({
fnKey: [FunctionKey.APPROVE_TOKEN, { tokenAddress: token.address }],
fn: (input: TrimmedApproveTokenInput) =>
callOrThrow({ tokenContract }, params =>
approveToken({
...input,
...params,
}),
),
{
...options,
onSuccess: async (...onSuccessParams) => {
const { spenderAddress } = onSuccessParams[1];
const accountAddress = await tokenContract?.signer.getAddress();
onConfirmed: async ({ input }) => {
const accountAddress = await tokenContract?.signer.getAddress();

queryClient.invalidateQueries([
FunctionKey.GET_TOKEN_ALLOWANCE,
{
tokenAddress: token.address,
spenderAddress,
accountAddress,
},
]);

if (options?.onSuccess) {
options.onSuccess(...onSuccessParams);
}
},
queryClient.invalidateQueries([
FunctionKey.GET_TOKEN_ALLOWANCE,
{
tokenAddress: token.address,
spenderAddress: input.spenderAddress,
accountAddress,
},
]);
},
);
options,
});
};

export default useApproveToken;
18 changes: 4 additions & 14 deletions src/clients/api/mutations/borrow/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import BigNumber from 'bignumber.js';
import { checkForTokenTransactionError } from 'errors';
import { VBep20 } from 'packages/contracts';

import fakeContractReceipt from '__mocks__/models/contractReceipt';
import fakeContractTransaction from '__mocks__/models/contractTransaction';

import borrow from '.';

vi.mock('errors/transactionErrors');

describe('api/mutation/borrow', () => {
describe('borrow', () => {
test('returns contract receipt when request succeeds', async () => {
const fakeAmountWei = new BigNumber('10000000000000000');
const waitMock = vi.fn(async () => fakeContractReceipt);
const borrowMock = vi.fn(() => ({
wait: waitMock,
}));
const borrowMock = vi.fn(async () => fakeContractTransaction);

const fakeContract = {
borrow: borrowMock,
Expand All @@ -25,12 +19,8 @@ describe('api/mutation/borrow', () => {
amountWei: fakeAmountWei,
});

expect(response).toBe(fakeContractReceipt);
expect(response).toBe(fakeContractTransaction);
expect(borrowMock).toHaveBeenCalledTimes(1);
expect(borrowMock).toHaveBeenCalledWith(fakeAmountWei.toFixed());
expect(waitMock).toBeCalledTimes(1);
expect(waitMock).toHaveBeenCalledWith(1);
expect(checkForTokenTransactionError).toHaveBeenCalledTimes(1);
expect(checkForTokenTransactionError).toHaveBeenCalledWith(fakeContractReceipt);
});
});
12 changes: 4 additions & 8 deletions src/clients/api/mutations/borrow/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import BigNumber from 'bignumber.js';
import { checkForTokenTransactionError } from 'errors';
import { ContractReceipt } from 'ethers';
import { ContractTransaction } from 'ethers';
import { VBep20, VBnb } from 'packages/contracts';

export interface BorrowInput {
vTokenContract: VBep20 | VBnb;
amountWei: BigNumber;
}

export type BorrowOutput = ContractReceipt;
export type BorrowOutput = ContractTransaction;

const borrow = async ({ vTokenContract, amountWei }: BorrowInput): Promise<BorrowOutput> => {
const transaction = await vTokenContract.borrow(amountWei.toFixed());
const receipt = await transaction.wait(1);
return checkForTokenTransactionError(receipt);
};
const borrow = async ({ vTokenContract, amountWei }: BorrowInput): Promise<BorrowOutput> =>
vTokenContract.borrow(amountWei.toFixed());

export default borrow;
69 changes: 31 additions & 38 deletions src/clients/api/mutations/borrow/useBorrow.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useAnalytics } from 'packages/analytics';
import { useGetVTokenContract } from 'packages/contracts';
import { MutationObserverOptions, useMutation } from 'react-query';
import { VToken } from 'types';
import { callOrThrow, convertWeiToTokens } from 'utilities';

import { BorrowInput, BorrowOutput, borrow, queryClient } from 'clients/api';
import { BorrowInput, borrow, queryClient } from 'clients/api';
import FunctionKey from 'constants/functionKey';
import { UseSendTransactionOptions, useSendTransaction } from 'hooks/useSendTransaction';

type TrimmedBorrowInput = Omit<BorrowInput, 'vTokenContract'>;
type Options = MutationObserverOptions<BorrowOutput, Error, TrimmedBorrowInput>;
type Options = UseSendTransactionOptions<TrimmedBorrowInput>;

const useBorrow = (
{ vToken, poolName }: { vToken: VToken; poolName: string },
Expand All @@ -17,48 +17,41 @@ const useBorrow = (
const vTokenContract = useGetVTokenContract({ vToken, passSigner: true });
const { captureAnalyticEvent } = useAnalytics();

return useMutation(
[FunctionKey.BORROW, { vToken }],
(input: TrimmedBorrowInput) =>
return useSendTransaction({
fnKey: [FunctionKey.BORROW, { vToken }],
fn: (input: TrimmedBorrowInput) =>
callOrThrow({ vTokenContract }, params =>
borrow({
...params,
...input,
}),
),
{
...options,
onSuccess: async (...onSuccessParams) => {
const { amountWei } = onSuccessParams[1];

captureAnalyticEvent('Tokens borrowed', {
poolName,
tokenSymbol: vToken.underlyingToken.symbol,
tokenAmountTokens: convertWeiToTokens({
token: vToken.underlyingToken,
valueWei: amountWei,
}).toNumber(),
});

const accountAddress = await vTokenContract?.signer.getAddress();

queryClient.invalidateQueries(FunctionKey.GET_V_TOKEN_BALANCES_ALL);
queryClient.invalidateQueries([
FunctionKey.GET_BALANCE_OF,
{
accountAddress,
vTokenAddress: vToken.address,
},
]);
queryClient.invalidateQueries(FunctionKey.GET_MAIN_MARKETS);
queryClient.invalidateQueries(FunctionKey.GET_ISOLATED_POOLS);

if (options?.onSuccess) {
options.onSuccess(...onSuccessParams);
}
},
onConfirmed: async ({ input }) => {
captureAnalyticEvent('Tokens borrowed', {
poolName,
tokenSymbol: vToken.underlyingToken.symbol,
tokenAmountTokens: convertWeiToTokens({
token: vToken.underlyingToken,
valueWei: input.amountWei,
}).toNumber(),
});

const accountAddress = await vTokenContract?.signer.getAddress();

queryClient.invalidateQueries(FunctionKey.GET_V_TOKEN_BALANCES_ALL);
queryClient.invalidateQueries([
FunctionKey.GET_BALANCE_OF,
{
accountAddress,
vTokenAddress: vToken.address,
},
]);
queryClient.invalidateQueries(FunctionKey.GET_MAIN_MARKETS);
queryClient.invalidateQueries(FunctionKey.GET_MAIN_POOL);
queryClient.invalidateQueries(FunctionKey.GET_ISOLATED_POOLS);
},
);
options,
});
};

export default useBorrow;
1 change: 1 addition & 0 deletions src/clients/api/mutations/claimRewards/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ const claimRewards = async ({
const receipt = await transaction.wait(1);

// Check for errors that did not revert the transaction
// TODO: remove once this function has been refactored to use useSendTransaction hook
checkForComptrollerTransactionError(receipt);
checkForTokenTransactionError(receipt);
checkForVaiControllerTransactionError(receipt);
Expand Down
1 change: 1 addition & 0 deletions src/clients/api/mutations/enterMarket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const enterMarket = async ({
}: EnterMarketInput): Promise<EnterMarketOutput> => {
const transaction = await comptrollerContract.enterMarkets([vToken.address]);
const receipt = await transaction.wait(1);
// TODO: remove check once this function has been refactored to use useSendTransaction hook
return checkForComptrollerTransactionError(receipt);
};

Expand Down
2 changes: 1 addition & 1 deletion src/clients/api/mutations/enterMarket/useEnterMarket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const useEnterMarket = (
userSupplyBalanceTokens: userSupplyBalanceTokens.toNumber(),
});

queryClient.invalidateQueries(FunctionKey.GET_MAIN_ASSETS_IN_ACCOUNT);
queryClient.invalidateQueries(FunctionKey.GET_MAIN_POOL);
queryClient.invalidateQueries(FunctionKey.GET_ISOLATED_POOLS);

if (options?.onSuccess) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const executeWithdrawalFromXvsVault = async ({
}: ExecuteWithdrawalFromXvsVaultInput): Promise<ExecuteWithdrawalFromXvsVaultOutput> => {
const transaction = await xvsVaultContract.executeWithdrawal(rewardTokenAddress, poolIndex);
const receipt = await transaction.wait(1);
// TODO: remove check once this function has been refactored to use useSendTransaction hook
return checkForXvsVaultProxyTransactionError(receipt);
};

Expand Down
1 change: 1 addition & 0 deletions src/clients/api/mutations/exitMarket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const exitMarket = async ({
}: ExitMarketInput): Promise<ExitMarketOutput> => {
const transaction = await comptrollerContract.exitMarket(vToken.address);
const receipt = await transaction.wait(1);
// TODO: remove check once this function has been refactored to use useSendTransaction hook
return checkForComptrollerTransactionError(receipt);
};

Expand Down
2 changes: 1 addition & 1 deletion src/clients/api/mutations/exitMarket/useExitMarket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const useExitMarket = (
userSupplyBalanceTokens: userSupplyBalanceTokens.toNumber(),
});

queryClient.invalidateQueries(FunctionKey.GET_MAIN_ASSETS_IN_ACCOUNT);
queryClient.invalidateQueries(FunctionKey.GET_MAIN_POOL);
queryClient.invalidateQueries(FunctionKey.GET_ISOLATED_POOLS);

if (options?.onSuccess) {
Expand Down
1 change: 1 addition & 0 deletions src/clients/api/mutations/mintVai/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const mintVai = async ({
}: MintVaiInput): Promise<MintVaiOutput> => {
const transaction = await vaiControllerContract.mintVAI(amountWei.toFixed());
const receipt = await transaction.wait(1);
// TODO: remove check once this function has been refactored to use useSendTransaction hook
return checkForVaiControllerTransactionError(receipt);
};

Expand Down
Loading

0 comments on commit f6420d5

Please sign in to comment.