vega-frontend-monorepo/apps/token/src/hooks/use-transaction.ts
Matthew Russell e463bbe238
feat(#495): get smart contracts addresses from network params
* feat: unhardcode contract addresses

* fix: linting and tests

* feat: switch contract usage in token app to use unhardcoded addresses

* chore: remove other usage of hard coded contract addresses

* feat: convert contracts to classes, update claim contract to fix circular dependency

* feat: add hard coded contract addresses to contracts page

* fix: misc tidy up

* chore: rename ethers big num conversion func

* fix: remove pending transactions modal

* chore: add single toBigNum function that can accept number string or EthersBignNumber

* chore: delete unused tranche helpers and decimals functions from smart contracts lib

* feat: add faucetable token class

* fix: reset tx state after early exit from approve tx

* feat: re add transaction modal using zustand store

* fix: loader colors for eth wallet

* fix: pass ethereum config to gurantee existence before tx execution

* chore: lint smart contracts lib

* chore: fix web3container to use children and not render prop

* chore: lint

* fix: use background to mock ethereum wallet to avoid mocking globally for every test

* chore: move web3 mock to common steps and call from withdrawals feature tests
2022-06-07 15:08:40 -07:00

136 lines
3.5 KiB
TypeScript

import React from 'react';
import * as Sentry from '@sentry/react';
import { useTranslation } from 'react-i18next';
import type { ethers } from 'ethers';
import { isUnexpectedError, isUserRejection } from '../lib/web3-utils';
import {
initialState,
TransactionActionType,
transactionReducer,
} from './transaction-reducer';
import { useTransactionStore } from '../stores/transactions';
export const useTransaction = (
performTransaction: () => Promise<ethers.ContractTransaction>,
requiredConfirmations = 1
) => {
const { t } = useTranslation();
const store = useTransactionStore();
const [state, dispatch] = React.useReducer(transactionReducer, {
...initialState,
requiredConfirmations,
});
const handleError = React.useCallback(
(err: Error) => {
if (isUnexpectedError(err)) {
Sentry.captureException(err);
}
if (isUserRejection(err)) {
dispatch({ type: TransactionActionType.TX_RESET });
return;
} else {
Sentry.captureException(err);
}
const defaultMessage = t('Something went wrong');
const errorSubstitutions = {
unknown: defaultMessage,
'Transaction has been reverted by the EVM': defaultMessage,
};
dispatch({
type: TransactionActionType.TX_ERROR,
error: err,
errorSubstitutions,
});
},
[dispatch, t]
);
const perform = React.useCallback(async () => {
dispatch({
type: TransactionActionType.TX_REQUESTED,
});
Sentry.addBreadcrumb({
type: 'Transaction',
level: Sentry.Severity.Log,
message: 'Transaction requested',
timestamp: Date.now(),
});
try {
const tx = await performTransaction();
store.add({ tx, receipt: null, pending: true, requiredConfirmations });
dispatch({
type: TransactionActionType.TX_SUBMITTED,
txHash: tx.hash,
});
Sentry.addBreadcrumb({
type: 'Transaction',
level: Sentry.Severity.Log,
message: 'Transaction submitted',
data: {
hash: tx.hash,
from: tx.from,
gasLimit: tx.gasLimit.toString(),
nonce: tx.nonce,
},
timestamp: Date.now(),
});
let receipt: ethers.ContractReceipt | null = null;
for (let i = 1; i <= requiredConfirmations; i++) {
receipt = await tx.wait(i);
store.update({ tx, receipt, pending: true, requiredConfirmations });
dispatch({
type: TransactionActionType.TX_CONFIRMATION,
confirmations: receipt.confirmations,
});
}
if (!receipt) {
throw new Error('No receipt after confirmations are met');
}
store.update({ tx, receipt, pending: false, requiredConfirmations });
dispatch({
type: TransactionActionType.TX_COMPLETE,
receipt,
confirmations: receipt.confirmations,
});
Sentry.addBreadcrumb({
type: 'Transaction',
level: Sentry.Severity.Log,
message: 'Transaction complete',
data: {
blockNumber: receipt.blockNumber,
confirmations: receipt.confirmations,
from: receipt.from,
to: receipt.to,
transactionHash: receipt.transactionHash,
},
timestamp: Date.now(),
});
} catch (err) {
handleError(err as Error);
}
}, [performTransaction, requiredConfirmations, handleError, store]);
const reset = () => {
dispatch({ type: TransactionActionType.TX_RESET });
};
return {
state,
dispatch,
perform,
reset,
};
};