import { mutationEventKey } from "../keys.js"; import type { BackwardCompatInputOptions, ChainComposableOptions, } from "../types.js"; import { tapTx } from "../utils/tap-tx.js"; import { useAsyncAction } from "./use-async-action.js"; import { useChainId } from "./use-chain-id.js"; import { useSigner } from "./use-signer.js"; import { useTypedApiPromise } from "./use-typed-api.js"; import type { ChainId } from "@reactive-dot/core"; import { BaseError, MutationError } from "@reactive-dot/core"; import { extractPolkadotSigner, type ChainDescriptorOf, type Signer, type TxOptionsOf, } from "@reactive-dot/core/internal.js"; import type { Transaction, TypedApi } from "polkadot-api"; import { from, switchMap } from "rxjs"; import { inject, toValue, type MaybeRefOrGetter } from "vue"; /** * Composable for sending transactions to chains. * * @param action - The function to create the transaction * @param options - Additional options * @returns The current transaction state & submit function */ export function useMutation< TAction extends ( tx: TypedApi>["tx"], // eslint-disable-next-line @typescript-eslint/no-explicit-any input: any, ) => Transaction, TChainId extends ChainId | undefined, >( action: TAction, options?: ChainComposableOptions & { /** * Override default signer */ signer?: MaybeRefOrGetter; /** * Additional transaction options */ txOptions?: MaybeRefOrGetter> | undefined>; }, ) { const injectedSigner = useSigner(); const typedApiPromise = useTypedApiPromise(); const chainId = useChainId(); const mutationEventRef = inject( mutationEventKey, () => { throw new BaseError("No mutation event ref provided"); }, true, ); type SubmitOptions = { signer?: Signer; txOptions?: TxOptionsOf>; } & (Parameters["length"] extends 2 ? BackwardCompatInputOptions[1]> : Partial[1]>>); return useAsyncAction( ( ...[submitOptions]: Parameters["length"] extends 2 ? [submitOptions: SubmitOptions] : [submitOptions?: SubmitOptions] ) => { const signer = extractPolkadotSigner( submitOptions?.signer ?? toValue(options?.signer) ?? injectedSigner, ); if (signer === undefined) { throw new MutationError("No signer provided"); } const id = globalThis.crypto.randomUUID(); return from(typedApiPromise.value).pipe( switchMap((typedApi) => { const transaction = action( typedApi.tx, submitOptions === undefined ? undefined : "input" in submitOptions ? submitOptions.input : "variables" in submitOptions ? submitOptions.variables : undefined, ); const eventProps = { id, chainId: chainId.value, call: transaction.decodedCall, }; mutationEventRef.value = { ...eventProps, status: "pending" }; return transaction .signSubmitAndWatch( signer, submitOptions?.txOptions ?? toValue(options?.txOptions), ) .pipe(tapTx(mutationEventRef, chainId.value, transaction)); }), ); }, ); }