From 7f86e040f6b3eac20202842c9c1e3a45e47fbd44 Mon Sep 17 00:00:00 2001 From: Nikita Yutanov Date: Mon, 2 Oct 2023 12:03:47 +0300 Subject: [PATCH] Add useSendMessage gas limit (#1418) --- utils/gear-hooks/package.json | 2 +- utils/gear-hooks/src/hooks/api/index.ts | 10 ++ .../src/hooks/api/useCalculateGas/index.ts | 18 +-- .../src/hooks/api/useCalculateGas/types.ts | 1 - .../src/hooks/api/useDepricatedSendMessage.ts | 124 ++++++++++++++++++ .../src/hooks/api/useSendMessage.ts | 90 ++++++------- utils/gear-hooks/src/hooks/index.ts | 6 + utils/gear-hooks/src/index.ts | 6 + 8 files changed, 198 insertions(+), 59 deletions(-) create mode 100644 utils/gear-hooks/src/hooks/api/useDepricatedSendMessage.ts diff --git a/utils/gear-hooks/package.json b/utils/gear-hooks/package.json index 1b101d1e17..6188314aa9 100644 --- a/utils/gear-hooks/package.json +++ b/utils/gear-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@gear-js/react-hooks", - "version": "0.6.10", + "version": "0.7.0", "description": "React hooks used across Gear applications", "author": "Gear Technologies", "license": "GPL-3.0", diff --git a/utils/gear-hooks/src/hooks/api/index.ts b/utils/gear-hooks/src/hooks/api/index.ts index def0a57408..87c3d9be5b 100644 --- a/utils/gear-hooks/src/hooks/api/index.ts +++ b/utils/gear-hooks/src/hooks/api/index.ts @@ -1,5 +1,12 @@ import { useReadFullState, useReadWasmState } from './useReadState'; + import { useSendMessage, SendMessageOptions, UseSendMessageOptions } from './useSendMessage'; +import { + useDepricatedSendMessage, + DepricatedSendMessageOptions, + UseDepricatedSendMessageOptions, +} from './useDepricatedSendMessage'; + import { useUploadProgram, useCreateProgram } from './useProgram'; import { useUploadCalculateGas, @@ -25,6 +32,9 @@ export { useVoucherBalance, useVoucher, useBalanceFormat, + useDepricatedSendMessage, + DepricatedSendMessageOptions, + UseDepricatedSendMessageOptions, SendMessageOptions, UseSendMessageOptions, }; diff --git a/utils/gear-hooks/src/hooks/api/useCalculateGas/index.ts b/utils/gear-hooks/src/hooks/api/useCalculateGas/index.ts index 2e11e5ba0a..d72f61fbc1 100644 --- a/utils/gear-hooks/src/hooks/api/useCalculateGas/index.ts +++ b/utils/gear-hooks/src/hooks/api/useCalculateGas/index.ts @@ -1,5 +1,5 @@ import { GasInfo, ProgramMetadata } from '@gear-js/api'; -import { AnyJson } from '@polkadot/types/types'; +import { AnyJson, AnyNumber } from '@polkadot/types/types'; import { HexString } from '@polkadot/util/types'; import { useContext } from 'react'; import { AccountContext, ApiContext } from 'context'; @@ -13,12 +13,12 @@ function useUploadCalculateGas( const { api } = useContext(ApiContext); // сircular dependency fix const { account } = useContext(AccountContext); - const calculateGas = (initPayload: AnyJson): Promise => { + const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0): Promise => { if (!account) return Promise.reject(new Error('No account address')); if (!code) return Promise.reject(new Error('No program source')); const { decodedAddress } = account; - const { value = 0, isOtherPanicsAllowed = false } = options || {}; + const { isOtherPanicsAllowed = false } = options || {}; return api.program.calculateGas.initUpload(decodedAddress, code, initPayload, value, isOtherPanicsAllowed, meta); }; @@ -30,12 +30,12 @@ function useCreateCalculateGas(codeId: HexString | undefined, meta?: ProgramMeta const { api } = useContext(ApiContext); // сircular dependency fix const { account } = useContext(AccountContext); - const calculateGas = (initPayload: AnyJson): Promise => { + const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0): Promise => { if (!account) return Promise.reject(new Error('No account address')); if (!codeId) return Promise.reject(new Error('No program source')); const { decodedAddress } = account; - const { value = 0, isOtherPanicsAllowed = false } = options || {}; + const { isOtherPanicsAllowed = false } = options || {}; return api.program.calculateGas.initCreate(decodedAddress, codeId, initPayload, value, isOtherPanicsAllowed, meta); }; @@ -51,12 +51,12 @@ function useHandleCalculateGas( const { api } = useContext(ApiContext); // сircular dependency fix const { account } = useContext(AccountContext); - const calculateGas = (initPayload: AnyJson): Promise => { + const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0): Promise => { if (!account) return Promise.reject(new Error('No account address')); if (!destinationId) return Promise.reject(new Error('No program source')); const { decodedAddress } = account; - const { value = 0, isOtherPanicsAllowed = false } = options || {}; + const { isOtherPanicsAllowed = false } = options || {}; return api.program.calculateGas.handle( decodedAddress, @@ -75,12 +75,12 @@ function useReplyCalculateGas(messageId: HexString | undefined, meta?: ProgramMe const { api } = useContext(ApiContext); // сircular dependency fix const { account } = useContext(AccountContext); - const calculateGas = (initPayload: AnyJson) => { + const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0) => { if (!account) return Promise.reject(new Error('No account address')); if (!messageId) return Promise.reject(new Error('No program source')); const { decodedAddress } = account; - const { value = 0, isOtherPanicsAllowed = false } = options || {}; + const { isOtherPanicsAllowed = false } = options || {}; return api.program.calculateGas.reply(decodedAddress, messageId, initPayload, value, isOtherPanicsAllowed, meta); }; diff --git a/utils/gear-hooks/src/hooks/api/useCalculateGas/types.ts b/utils/gear-hooks/src/hooks/api/useCalculateGas/types.ts index 141445eac6..66bb5cce7c 100644 --- a/utils/gear-hooks/src/hooks/api/useCalculateGas/types.ts +++ b/utils/gear-hooks/src/hooks/api/useCalculateGas/types.ts @@ -4,7 +4,6 @@ import { AnyJson, AnyNumber } from '@polkadot/types/types'; type CalculateGas = (initPayload: AnyJson) => Promise; type Options = { - value?: AnyNumber; isOtherPanicsAllowed?: boolean; }; diff --git a/utils/gear-hooks/src/hooks/api/useDepricatedSendMessage.ts b/utils/gear-hooks/src/hooks/api/useDepricatedSendMessage.ts new file mode 100644 index 0000000000..617e344a2e --- /dev/null +++ b/utils/gear-hooks/src/hooks/api/useDepricatedSendMessage.ts @@ -0,0 +1,124 @@ +import { ProgramMetadata } from '@gear-js/api'; +import { web3FromSource } from '@polkadot/extension-dapp'; +import { EventRecord } from '@polkadot/types/interfaces'; +import { AnyJson, ISubmittableResult } from '@polkadot/types/types'; +import { HexString } from '@polkadot/util/types'; +import { useContext } from 'react'; +import { AccountContext, AlertContext, ApiContext } from 'context'; +import { DEFAULT_ERROR_OPTIONS, DEFAULT_SUCCESS_OPTIONS } from 'consts'; +import { getAutoGasLimit, getExtrinsicFailedMessage } from 'utils'; + +type UseDepricatedSendMessageOptions = { + isMaxGasLimit?: boolean; + disableAlerts?: boolean; +}; + +type DepricatedSendMessageOptions = { + value?: string | number; + prepaid?: boolean; + isOtherPanicsAllowed?: boolean; + onSuccess?: () => void; + onError?: () => void; +}; + +const MAX_GAS_LIMIT = 250000000000; + +function useDepricatedSendMessage( + destination: HexString, + metadata: ProgramMetadata | undefined, + { isMaxGasLimit = false, disableAlerts }: UseDepricatedSendMessageOptions = {}, +) { + const { api } = useContext(ApiContext); // сircular dependency fix + const { account } = useContext(AccountContext); + const alert = useContext(AlertContext); + + const title = 'gear.sendMessage'; + + const handleEventsStatus = (events: EventRecord[], onSuccess?: () => void, onError?: () => void) => { + events.forEach(({ event }) => { + const { method, section } = event; + + if (method === 'MessageQueued') { + if (!disableAlerts) alert.success(`${section}.MessageQueued`); + + onSuccess && onSuccess(); + } else if (method === 'ExtrinsicFailed') { + const message = getExtrinsicFailedMessage(api, event); + + console.error(message); + alert.error(message, { title }); + + onError && onError(); + } + }); + }; + + const handleStatus = (result: ISubmittableResult, alertId: string, onSuccess?: () => void, onError?: () => void) => { + const { status, events } = result; + const { isReady, isInBlock, isInvalid, isFinalized } = status; + + if (isInvalid) { + if (alertId) { + alert.update(alertId, 'Transaction error. Status: isInvalid', DEFAULT_ERROR_OPTIONS); + } else { + alert.error('Transaction error. Status: isInvalid'); + } + } else if (isReady && alertId) { + alert.update(alertId, 'Ready'); + } else if (isInBlock && alertId) { + alert.update(alertId, 'In Block'); + } else if (isFinalized) { + if (alertId) alert.update(alertId, 'Finalized', DEFAULT_SUCCESS_OPTIONS); + + handleEventsStatus(events, onSuccess, onError); + } + }; + + const sendMessage = (payload: AnyJson, options?: DepricatedSendMessageOptions) => { + if (account && metadata) { + const alertId = disableAlerts ? '' : alert.loading('Sign In', { title }); + + const { value = 0, isOtherPanicsAllowed = false, prepaid = false, onSuccess, onError } = options || {}; + const { address, decodedAddress, meta } = account; + const { source } = meta; + + const getGasLimit = isMaxGasLimit + ? Promise.resolve(MAX_GAS_LIMIT) + : api.program.calculateGas + .handle(decodedAddress, destination, payload, value, isOtherPanicsAllowed, metadata) + .then(getAutoGasLimit); + + getGasLimit + .then((gasLimit) => ({ + destination, + gasLimit, + payload, + value, + prepaid, + account: prepaid ? decodedAddress : undefined, + })) + .then((message) => api.message.send(message, metadata)) + .then(() => web3FromSource(source)) + .then(({ signer }) => + api.message.signAndSend(address, { signer }, (result) => handleStatus(result, alertId, onSuccess, onError)), + ) + .catch((error: Error) => { + const { message } = error; + + console.error(error); + + if (alertId) { + alert.update(alertId, message, DEFAULT_ERROR_OPTIONS); + } else { + alert.error(message); + } + + onError && onError(); + }); + } + }; + + return sendMessage; +} + +export { useDepricatedSendMessage, DepricatedSendMessageOptions, UseDepricatedSendMessageOptions }; diff --git a/utils/gear-hooks/src/hooks/api/useSendMessage.ts b/utils/gear-hooks/src/hooks/api/useSendMessage.ts index faed284af1..048bb34904 100644 --- a/utils/gear-hooks/src/hooks/api/useSendMessage.ts +++ b/utils/gear-hooks/src/hooks/api/useSendMessage.ts @@ -1,4 +1,4 @@ -import { ProgramMetadata } from '@gear-js/api'; +import { GasLimit, ProgramMetadata } from '@gear-js/api'; import { web3FromSource } from '@polkadot/extension-dapp'; import { EventRecord } from '@polkadot/types/interfaces'; import { AnyJson, ISubmittableResult } from '@polkadot/types/types'; @@ -6,7 +6,7 @@ import { HexString } from '@polkadot/util/types'; import { useContext } from 'react'; import { AccountContext, AlertContext, ApiContext } from 'context'; import { DEFAULT_ERROR_OPTIONS, DEFAULT_SUCCESS_OPTIONS } from 'consts'; -import { getAutoGasLimit, getExtrinsicFailedMessage } from 'utils'; +import { getExtrinsicFailedMessage } from 'utils'; type UseSendMessageOptions = { isMaxGasLimit?: boolean; @@ -14,19 +14,18 @@ type UseSendMessageOptions = { }; type SendMessageOptions = { + payload: AnyJson; + gasLimit: GasLimit; value?: string | number; prepaid?: boolean; - isOtherPanicsAllowed?: boolean; onSuccess?: () => void; onError?: () => void; }; -const MAX_GAS_LIMIT = 250000000000; - function useSendMessage( destination: HexString, metadata: ProgramMetadata | undefined, - { isMaxGasLimit = false, disableAlerts }: UseSendMessageOptions = {}, + { disableAlerts }: UseSendMessageOptions = {}, ) { const { api } = useContext(ApiContext); // сircular dependency fix const { account } = useContext(AccountContext); @@ -74,48 +73,43 @@ function useSendMessage( } }; - const sendMessage = (payload: AnyJson, options?: SendMessageOptions) => { - if (account && metadata) { - const alertId = disableAlerts ? '' : alert.loading('Sign In', { title }); - - const { value = 0, isOtherPanicsAllowed = false, prepaid = false, onSuccess, onError } = options || {}; - const { address, decodedAddress, meta } = account; - const { source } = meta; - - const getGasLimit = isMaxGasLimit - ? Promise.resolve(MAX_GAS_LIMIT) - : api.program.calculateGas - .handle(decodedAddress, destination, payload, value, isOtherPanicsAllowed, metadata) - .then(getAutoGasLimit); - - getGasLimit - .then((gasLimit) => ({ - destination, - gasLimit, - payload, - value, - prepaid, - account: prepaid ? decodedAddress : undefined, - })) - .then((message) => api.message.send(message, metadata)) - .then(() => web3FromSource(source)) - .then(({ signer }) => - api.message.signAndSend(address, { signer }, (result) => handleStatus(result, alertId, onSuccess, onError)), - ) - .catch((error: Error) => { - const { message } = error; - - console.error(error); - - if (alertId) { - alert.update(alertId, message, DEFAULT_ERROR_OPTIONS); - } else { - alert.error(message); - } - - onError && onError(); - }); - } + const sendMessage = (args: SendMessageOptions) => { + if (!account || !metadata) return; + + const alertId = disableAlerts ? '' : alert.loading('Sign In', { title }); + + const { payload, gasLimit, value = 0, prepaid = false, onSuccess, onError } = args; + const { address, decodedAddress, meta } = account; + const { source } = meta; + + const message = { + destination, + payload, + gasLimit, + value, + prepaid, + account: prepaid ? decodedAddress : undefined, + }; + + api.message + .send(message, metadata) + .then(() => web3FromSource(source)) + .then(({ signer }) => + api.message.signAndSend(address, { signer }, (result) => handleStatus(result, alertId, onSuccess, onError)), + ) + .catch((error: Error) => { + const { message } = error; + + console.error(error); + + if (alertId) { + alert.update(alertId, message, DEFAULT_ERROR_OPTIONS); + } else { + alert.error(message); + } + + onError && onError(); + }); }; return sendMessage; diff --git a/utils/gear-hooks/src/hooks/index.ts b/utils/gear-hooks/src/hooks/index.ts index f006a7fae2..46d30a6e5d 100644 --- a/utils/gear-hooks/src/hooks/index.ts +++ b/utils/gear-hooks/src/hooks/index.ts @@ -14,6 +14,9 @@ import { useBalanceFormat, SendMessageOptions, UseSendMessageOptions, + useDepricatedSendMessage, + DepricatedSendMessageOptions, + UseDepricatedSendMessageOptions, } from './api'; import { useAccount, useAlert, useApi } from './context'; import { useCreateHandler } from './handlers'; @@ -36,6 +39,9 @@ export { useAlert, useApi, useCreateHandler, + useDepricatedSendMessage, + DepricatedSendMessageOptions, + UseDepricatedSendMessageOptions, SendMessageOptions, UseSendMessageOptions, }; diff --git a/utils/gear-hooks/src/index.ts b/utils/gear-hooks/src/index.ts index 18c72ac053..b06a594969 100644 --- a/utils/gear-hooks/src/index.ts +++ b/utils/gear-hooks/src/index.ts @@ -18,6 +18,9 @@ import { useCreateHandler, SendMessageOptions, UseSendMessageOptions, + useDepricatedSendMessage, + DepricatedSendMessageOptions, + UseDepricatedSendMessageOptions, } from './hooks'; import { withoutCommas } from './utils'; @@ -67,6 +70,7 @@ export { AlertProvider, useCreateHandler, withoutCommas, + useDepricatedSendMessage, DEFAULT_OPTIONS, DEFAULT_INFO_OPTIONS, DEFAULT_ERROR_OPTIONS, @@ -84,4 +88,6 @@ export { Account, SendMessageOptions, UseSendMessageOptions, + DepricatedSendMessageOptions, + UseDepricatedSendMessageOptions, };