// Copyright 2017-2026 @pezkuwi/react-hooks authors & contributors // SPDX-License-Identifier: Apache-2.0 import type { Call } from '@pezkuwi/types/interfaces'; import type { ICompact, INumber } from '@pezkuwi/types/types'; import type { BN } from '@pezkuwi/util'; import type { V2WeightConstruct, WeightResult } from './types.js'; import { useEffect, useState } from 'react'; import { BN_ZERO, isFunction, nextTick, objectSpread } from '@pezkuwi/util'; import { createNamedHook } from './createNamedHook.js'; import { useApi } from './useApi.js'; import { useIsMountedRef } from './useIsMountedRef.js'; type V1Weight = INumber; export interface V2Weight { refTime: ICompact; proofSize: ICompact; } interface Result extends WeightResult { encodedCallLength: number; isWeightV2: boolean; weight: BN | V2WeightConstruct; } // this is 32 bytes in length, it allows construction for both AccountId32 & AccountId20 export const ZERO_ACCOUNT = '0x9876543210abcdef9876543210abcdef9876543210abcdef9876543210abcdef'; const EMPTY_STATE: Partial = { encodedCallLength: 0, v1Weight: BN_ZERO, v2Weight: { refTime: BN_ZERO }, weight: BN_ZERO }; // return both v1 & v2 weight structures (would depend on actual use) export function convertWeight (weight: V1Weight | V2Weight): WeightResult { // We need to handle it because sometimes input parameters are passed with type casting, // which can result in them being undefined or null under certain conditions. if (!weight) { const refTime = BN_ZERO; return { v1Weight: refTime, v2Weight: { proofSize: BN_ZERO, refTime } }; } if ((weight as V2Weight).proofSize) { // V2 weight const refTime = (weight as V2Weight).refTime.toBn(); return { v1Weight: refTime, v2Weight: weight as V2Weight }; } else if ((weight as V2Weight).refTime) { // V1.5 weight (when not converted) const refTime = (weight as V2Weight).refTime.toBn(); return { v1Weight: refTime, v2Weight: { proofSize: BN_ZERO, refTime } }; } // V1 weight const refTime = (weight as V1Weight).toBn(); return { v1Weight: refTime, v2Weight: { proofSize: BN_ZERO, refTime } }; } // for a given call, calculate the weight function useWeightImpl (call?: Call | null): Result { const { api } = useApi(); const mountedRef = useIsMountedRef(); const [state, setState] = useState(() => objectSpread({ // eslint-disable-next-line @typescript-eslint/unbound-method isWeightV2: !isFunction(api.registry.createType('Weight').toBn) }, EMPTY_STATE)); useEffect((): void => { if (call && api.call.transactionPaymentApi) { nextTick(async (): Promise => { try { const { v1Weight, v2Weight } = convertWeight( (await api.tx(call).paymentInfo(ZERO_ACCOUNT)).weight ); mountedRef.current && setState((prev) => objectSpread({}, prev, { encodedCallLength: call.encodedLength, v1Weight, v2Weight, weight: prev.isWeightV2 ? v2Weight : v1Weight }) ); } catch (error) { console.error(error); } }); } else { setState((prev) => objectSpread({}, prev, EMPTY_STATE) ); } }, [api, call, mountedRef]); return state; } export const useWeight = createNamedHook('useWeight', useWeightImpl);