146 lines
3.5 KiB
TypeScript
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,
|
|
};
|
|
};
|