From a66e14bf656a3eeb751557c2361a91348f27e8bd Mon Sep 17 00:00:00 2001 From: Nikita Yutanov Date: Fri, 5 Jul 2024 03:06:41 +0300 Subject: [PATCH] Add useTransaction hook --- .../src/pages/programs/ui/use-transaction.ts | 37 +++++++++++++++++++ utils/gear-hooks/src/hooks/index.ts | 3 +- utils/gear-hooks/src/hooks/sails/index.ts | 3 +- .../src/hooks/sails/use-transaction.ts | 37 +++++++++++++++++++ utils/gear-hooks/src/index.ts | 2 + 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 idea/frontend/src/pages/programs/ui/use-transaction.ts create mode 100644 utils/gear-hooks/src/hooks/sails/use-transaction.ts diff --git a/idea/frontend/src/pages/programs/ui/use-transaction.ts b/idea/frontend/src/pages/programs/ui/use-transaction.ts new file mode 100644 index 0000000000..7d583a3244 --- /dev/null +++ b/idea/frontend/src/pages/programs/ui/use-transaction.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { useAccount } from '@gear-js/react-hooks'; +import { web3FromSource } from '@polkadot/extension-dapp'; +import { TransactionBuilder } from 'sails-js'; + +type FunctionName = { + [K in keyof T]: T[K] extends (...args: any[]) => TransactionBuilder ? K : never; +}[keyof T]; + +type NonServiceKeys = 'api' | 'registry' | 'programId' | 'newCtorFromCode' | 'newCtorFromCodeId'; + +function useTransaction< + TProgram, + TServiceName extends Exclude, + TFunctionName extends FunctionName, +>(program: TProgram | undefined, serviceName: TServiceName, functionName: TFunctionName) { + const { account } = useAccount(); + + type FunctionType = TProgram[TServiceName][TFunctionName] extends (...args: infer A) => TransactionBuilder + ? (...args: A) => TransactionBuilder + : never; + + return async (...args: Parameters) => { + if (!program) throw new Error('Program is not found'); + if (!account) throw new Error('Account is not found'); + + const transaction = (program[serviceName][functionName] as FunctionType)(...args) as ReturnType; + + const { address, meta } = account; + const { signer } = await web3FromSource(meta.source); + transaction.withAccount(address, { signer }); + + return transaction; + }; +} + +export { useTransaction }; diff --git a/utils/gear-hooks/src/hooks/index.ts b/utils/gear-hooks/src/hooks/index.ts index 90bf6c57ab..1e97fb06c6 100644 --- a/utils/gear-hooks/src/hooks/index.ts +++ b/utils/gear-hooks/src/hooks/index.ts @@ -36,7 +36,7 @@ import { UseSendMessageWithGasOptions, SendMessageWithGasOptions, } from './handlers'; -import { useProgram, UseProgramParameters } from './sails'; +import { useProgram, UseProgramParameters, useTransaction } from './sails'; export { useReadFullState, @@ -72,6 +72,7 @@ export { useIssuedVouchers, useAccountIssuedVouchers, useProgram, + useTransaction, }; export type { diff --git a/utils/gear-hooks/src/hooks/sails/index.ts b/utils/gear-hooks/src/hooks/sails/index.ts index 3fcf53104e..634c628a01 100644 --- a/utils/gear-hooks/src/hooks/sails/index.ts +++ b/utils/gear-hooks/src/hooks/sails/index.ts @@ -1,4 +1,5 @@ import { useProgram, UseProgramParameters } from './use-program'; +import { useTransaction } from './use-transaction'; -export { useProgram }; +export { useProgram, useTransaction }; export type { UseProgramParameters }; diff --git a/utils/gear-hooks/src/hooks/sails/use-transaction.ts b/utils/gear-hooks/src/hooks/sails/use-transaction.ts new file mode 100644 index 0000000000..7d583a3244 --- /dev/null +++ b/utils/gear-hooks/src/hooks/sails/use-transaction.ts @@ -0,0 +1,37 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { useAccount } from '@gear-js/react-hooks'; +import { web3FromSource } from '@polkadot/extension-dapp'; +import { TransactionBuilder } from 'sails-js'; + +type FunctionName = { + [K in keyof T]: T[K] extends (...args: any[]) => TransactionBuilder ? K : never; +}[keyof T]; + +type NonServiceKeys = 'api' | 'registry' | 'programId' | 'newCtorFromCode' | 'newCtorFromCodeId'; + +function useTransaction< + TProgram, + TServiceName extends Exclude, + TFunctionName extends FunctionName, +>(program: TProgram | undefined, serviceName: TServiceName, functionName: TFunctionName) { + const { account } = useAccount(); + + type FunctionType = TProgram[TServiceName][TFunctionName] extends (...args: infer A) => TransactionBuilder + ? (...args: A) => TransactionBuilder + : never; + + return async (...args: Parameters) => { + if (!program) throw new Error('Program is not found'); + if (!account) throw new Error('Account is not found'); + + const transaction = (program[serviceName][functionName] as FunctionType)(...args) as ReturnType; + + const { address, meta } = account; + const { signer } = await web3FromSource(meta.source); + transaction.withAccount(address, { signer }); + + return transaction; + }; +} + +export { useTransaction }; diff --git a/utils/gear-hooks/src/index.ts b/utils/gear-hooks/src/index.ts index a97936c932..a61cb812d5 100644 --- a/utils/gear-hooks/src/index.ts +++ b/utils/gear-hooks/src/index.ts @@ -39,6 +39,7 @@ import { SendMessageWithGasOptions, useProgram, UseProgramParameters, + useTransaction, } from './hooks'; import { withoutCommas, getVaraAddress, getTypedEntries } from './utils'; @@ -109,6 +110,7 @@ export { useIssuedVouchers, useAccountIssuedVouchers, useProgram, + useTransaction, DEFAULT_OPTIONS, DEFAULT_INFO_OPTIONS, DEFAULT_ERROR_OPTIONS,