vega-frontend-monorepo/libs/wallet/src/use-vega-transaction.tsx

146 lines
3.5 KiB
TypeScript

import type { ReactNode } from 'react';
import { useCallback, useMemo, useState } from 'react';
import {
WalletClientError,
WalletHttpError,
} from '@vegaprotocol/wallet-client';
import { useVegaWallet } from './use-vega-wallet';
import type { VegaTransactionContentMap } from './vega-transaction-dialog';
import { VegaTransactionDialog } from './vega-transaction-dialog';
import type { Intent } from '@vegaprotocol/ui-toolkit';
import type { Transaction } from './connectors';
import type { WalletError } from './connectors';
import { ClientErrors } from './connectors';
export interface DialogProps {
intent?: Intent;
title?: string;
icon?: ReactNode;
content?: VegaTransactionContentMap;
}
export enum VegaTxStatus {
Default = 'Default',
Requested = 'Requested',
Pending = 'Pending',
Error = 'Error',
Complete = 'Complete',
}
export interface VegaTxState {
status: VegaTxStatus;
error: Error | null;
txHash: string | null;
signature: string | null;
dialogOpen: boolean;
}
export const initialState = {
status: VegaTxStatus.Default,
error: null,
txHash: null,
signature: null,
dialogOpen: false,
};
export const orderErrorResolve = (err: Error | unknown): Error => {
if (err instanceof WalletClientError) {
return err;
} else if (err instanceof WalletHttpError) {
return ClientErrors.UNKNOWN;
} else if (err instanceof TypeError) {
return ClientErrors.NO_SERVICE;
} else if (err instanceof Error) {
return err;
}
return ClientErrors.UNKNOWN;
};
export const useVegaTransaction = () => {
const { sendTx, disconnect } = useVegaWallet();
const [transaction, _setTransaction] = useState<VegaTxState>(initialState);
const setTransaction = useCallback((update: Partial<VegaTxState>) => {
_setTransaction((curr) => ({
...curr,
...update,
}));
}, []);
const reset = useCallback(() => {
setTransaction(initialState);
}, [setTransaction]);
const setComplete = useCallback(() => {
setTransaction({ status: VegaTxStatus.Complete });
}, [setTransaction]);
const send = useCallback(
async (pubKey: string, tx: Transaction) => {
try {
setTransaction({
error: null,
txHash: null,
signature: null,
status: VegaTxStatus.Requested,
dialogOpen: true,
});
const res = await sendTx(pubKey, tx);
if (res === null) {
// User rejected
reset();
return null;
}
if (res.signature && res.transactionHash) {
setTransaction({
status: VegaTxStatus.Pending,
txHash: res.transactionHash,
signature: res.signature,
});
return res;
}
return null;
} catch (err) {
const error = orderErrorResolve(err);
if ((error as WalletError).code === ClientErrors.NO_SERVICE.code) {
disconnect();
}
setTransaction({
error,
status: VegaTxStatus.Error,
});
return null;
}
},
[sendTx, setTransaction, reset, disconnect]
);
const Dialog = useMemo(() => {
return (props: DialogProps) => (
<VegaTransactionDialog
{...props}
isOpen={transaction.dialogOpen}
onChange={(isOpen) => {
if (!isOpen) reset();
setTransaction({ dialogOpen: isOpen });
}}
transaction={transaction}
/>
);
}, [transaction, setTransaction, reset]);
return {
send,
transaction,
reset,
setComplete,
setTransaction,
Dialog,
};
};