Skip to content

Commit

Permalink
Add useSendMessage gas limit (#1418)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitayutanov authored Oct 2, 2023
1 parent bdc3a2a commit 7f86e04
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 59 deletions.
2 changes: 1 addition & 1 deletion utils/gear-hooks/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
10 changes: 10 additions & 0 deletions utils/gear-hooks/src/hooks/api/index.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -25,6 +32,9 @@ export {
useVoucherBalance,
useVoucher,
useBalanceFormat,
useDepricatedSendMessage,
DepricatedSendMessageOptions,
UseDepricatedSendMessageOptions,
SendMessageOptions,
UseSendMessageOptions,
};
18 changes: 9 additions & 9 deletions utils/gear-hooks/src/hooks/api/useCalculateGas/index.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -13,12 +13,12 @@ function useUploadCalculateGas(
const { api } = useContext(ApiContext); // сircular dependency fix
const { account } = useContext(AccountContext);

const calculateGas = (initPayload: AnyJson): Promise<GasInfo> => {
const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0): Promise<GasInfo> => {
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);
};
Expand All @@ -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<GasInfo> => {
const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0): Promise<GasInfo> => {
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);
};
Expand All @@ -51,12 +51,12 @@ function useHandleCalculateGas(
const { api } = useContext(ApiContext); // сircular dependency fix
const { account } = useContext(AccountContext);

const calculateGas = (initPayload: AnyJson): Promise<GasInfo> => {
const calculateGas = (initPayload: AnyJson, value: AnyNumber = 0): Promise<GasInfo> => {
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,
Expand All @@ -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);
};
Expand Down
1 change: 0 additions & 1 deletion utils/gear-hooks/src/hooks/api/useCalculateGas/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { AnyJson, AnyNumber } from '@polkadot/types/types';
type CalculateGas = (initPayload: AnyJson) => Promise<GasInfo>;

type Options = {
value?: AnyNumber;
isOtherPanicsAllowed?: boolean;
};

Expand Down
124 changes: 124 additions & 0 deletions utils/gear-hooks/src/hooks/api/useDepricatedSendMessage.ts
Original file line number Diff line number Diff line change
@@ -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 };
90 changes: 42 additions & 48 deletions utils/gear-hooks/src/hooks/api/useSendMessage.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
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';
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;
disableAlerts?: boolean;
};

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);
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions utils/gear-hooks/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import {
useBalanceFormat,
SendMessageOptions,
UseSendMessageOptions,
useDepricatedSendMessage,
DepricatedSendMessageOptions,
UseDepricatedSendMessageOptions,
} from './api';
import { useAccount, useAlert, useApi } from './context';
import { useCreateHandler } from './handlers';
Expand All @@ -36,6 +39,9 @@ export {
useAlert,
useApi,
useCreateHandler,
useDepricatedSendMessage,
DepricatedSendMessageOptions,
UseDepricatedSendMessageOptions,
SendMessageOptions,
UseSendMessageOptions,
};
6 changes: 6 additions & 0 deletions utils/gear-hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import {
useCreateHandler,
SendMessageOptions,
UseSendMessageOptions,
useDepricatedSendMessage,
DepricatedSendMessageOptions,
UseDepricatedSendMessageOptions,
} from './hooks';

import { withoutCommas } from './utils';
Expand Down Expand Up @@ -67,6 +70,7 @@ export {
AlertProvider,
useCreateHandler,
withoutCommas,
useDepricatedSendMessage,
DEFAULT_OPTIONS,
DEFAULT_INFO_OPTIONS,
DEFAULT_ERROR_OPTIONS,
Expand All @@ -84,4 +88,6 @@ export {
Account,
SendMessageOptions,
UseSendMessageOptions,
DepricatedSendMessageOptions,
UseDepricatedSendMessageOptions,
};

0 comments on commit 7f86e04

Please sign in to comment.