From 2b705159c160e21b6391505a82e591f627ff5424 Mon Sep 17 00:00:00 2001 From: sokolova-an Date: Wed, 20 Nov 2024 19:59:33 +0700 Subject: [PATCH 1/4] feat: update types and checks for multisigs --- .../transaction/lib/transactionService.ts | 2 +- .../wallet/lib/__tests__/wallet-utils.test.ts | 16 ++++++++++++++-- .../entities/wallet/lib/account-utils.ts | 9 +++++++-- .../entities/wallet/lib/permission-utils.ts | 3 --- src/renderer/entities/wallet/lib/wallet-utils.ts | 11 ++++++++--- .../model/flexible-multisig-create.ts | 6 ++---- .../Delegate/ui/Confirmation.tsx | 2 +- .../EditDelegation/ui/Confirmation.tsx | 2 +- .../Nominate/ui/Confirmation.tsx | 2 +- .../OperationsConfirm/Payee/ui/Confirmation.tsx | 2 +- .../Restake/ui/Confirmation.tsx | 2 +- .../Unstake/ui/Confirmation.tsx | 2 +- .../Withdraw/ui/Confirmation.tsx | 2 +- .../features/proxy-add-pure/model/form-model.ts | 4 ++-- .../features/proxy-add/model/form-model.ts | 4 ++-- .../proxy-remove-pure/model/form-model.ts | 4 ++-- .../features/proxy-remove/model/form-model.ts | 4 ++-- .../ui/components/WalletDetails.tsx | 1 + .../ui/wallets/MultisigWalletDetails.tsx | 10 ++++++++-- .../service/walletSelectService.ts | 2 +- .../wallet-select/service/walletSelectService.ts | 2 +- .../components/ActionSteps/Confirmation.tsx | 13 ++++++++++--- .../pages/Operations/components/Details.tsx | 6 ++++-- .../components/EmptyState/EmptyOperations.tsx | 4 ++-- .../pages/Operations/components/LogModal.tsx | 7 ++++--- .../pages/Operations/components/Operation.tsx | 8 ++++---- .../components/OperationCardDetails.tsx | 6 ++++-- .../Operations/components/OperationFullInfo.tsx | 8 ++++---- .../components/OperationSignatories.tsx | 6 ++++-- .../Operations/components/modals/ApproveTx.tsx | 7 ++++--- .../Operations/components/modals/RejectTx.tsx | 15 +++++++++++---- .../processes/multisigs/model/multisigs-model.ts | 3 +-- src/renderer/shared/api/storage/lib/types.ts | 2 ++ src/renderer/shared/core/index.ts | 1 + src/renderer/shared/core/types/account.ts | 2 +- src/renderer/shared/core/types/notification.ts | 1 - src/renderer/shared/core/types/transaction.ts | 4 ++++ .../UnlockModal/ui/UnlockConfirmation.tsx | 2 +- 38 files changed, 119 insertions(+), 68 deletions(-) diff --git a/src/renderer/entities/transaction/lib/transactionService.ts b/src/renderer/entities/transaction/lib/transactionService.ts index 7301b4efd0..3867cde82f 100644 --- a/src/renderer/entities/transaction/lib/transactionService.ts +++ b/src/renderer/entities/transaction/lib/transactionService.ts @@ -175,7 +175,7 @@ type TxWrappersParams = { * @returns {Array} */ function getTxWrappers({ wallet, ...params }: TxWrappersParams): TxWrapper[] { - if (walletUtils.isMultisig(wallet)) { + if (walletUtils.isRegularMultisig(wallet)) { return getMultisigWrapper(params); } diff --git a/src/renderer/entities/wallet/lib/__tests__/wallet-utils.test.ts b/src/renderer/entities/wallet/lib/__tests__/wallet-utils.test.ts index bfc5e8c02d..c54bfe268e 100644 --- a/src/renderer/entities/wallet/lib/__tests__/wallet-utils.test.ts +++ b/src/renderer/entities/wallet/lib/__tests__/wallet-utils.test.ts @@ -29,13 +29,25 @@ describe('entities/wallet/lib/wallet-utils', () => { test('isMultisig should return true when wallet type is Multisig', () => { const wallet = { type: WalletType.MULTISIG } as Wallet; + expect(walletUtils.isRegularMultisig(wallet)).toEqual(true); + }); + + test('isFlexibleMultisig should return true when wallet type is Flexible Multisig', () => { + const wallet = { type: WalletType.FLEXIBLE_MULTISIG } as Wallet; + + expect(walletUtils.isFlexibleMultisig(wallet)).toEqual(true); + }); + + test('isMultisig should return true when wallet type is Flexible Multisig', () => { + const wallet = { type: WalletType.FLEXIBLE_MULTISIG } as Wallet; + expect(walletUtils.isMultisig(wallet)).toEqual(true); }); test('isMultisig should return false when wallet type is not Multisig', () => { const wallet = { type: WalletType.NOVA_WALLET } as Wallet; - expect(walletUtils.isMultisig(wallet)).toEqual(false); + expect(walletUtils.isRegularMultisig(wallet)).toEqual(false); }); test('isNovaWallet should return true when wallet type is NovaWallet', () => { @@ -47,7 +59,7 @@ describe('entities/wallet/lib/wallet-utils', () => { test('isNovaWallet should return false when wallet type is not NovaWallet', () => { const wallet = { type: WalletType.POLKADOT_VAULT } as Wallet; - expect(walletUtils.isMultisig(wallet)).toEqual(false); + expect(walletUtils.isRegularMultisig(wallet)).toEqual(false); }); test('isProxied should return true when wallet type is Proxied', () => { diff --git a/src/renderer/entities/wallet/lib/account-utils.ts b/src/renderer/entities/wallet/lib/account-utils.ts index aba06bf17d..b0adfee2b2 100644 --- a/src/renderer/entities/wallet/lib/account-utils.ts +++ b/src/renderer/entities/wallet/lib/account-utils.ts @@ -28,8 +28,9 @@ import { walletUtils } from './wallet-utils'; export const accountUtils = { isBaseAccount, isChainAccount, - isMultisigAccount, + isRegularMultisigAccount, isFlexibleMultisigAccount, + isMultisigAccount, isWcAccount, isProxiedAccount, isPureProxiedAccount, @@ -74,7 +75,7 @@ function isShardAccount(account: Partial): account is ShardAccount { return account.type === AccountType.SHARD; } -function isMultisigAccount(account: Partial): account is MultisigAccount { +function isRegularMultisigAccount(account: Partial): account is MultisigAccount { return account.type === AccountType.MULTISIG; } @@ -82,6 +83,10 @@ function isFlexibleMultisigAccount(account: Partial): account is Flexib return account.type === AccountType.FLEXIBLE_MULTISIG; } +function isMultisigAccount(account: Partial): account is MultisigAccount | FlexibleMultisigAccount { + return isFlexibleMultisigAccount(account) || isRegularMultisigAccount(account); +} + function isProxiedAccount(account: Partial): account is ProxiedAccount { return account.type === AccountType.PROXIED; } diff --git a/src/renderer/entities/wallet/lib/permission-utils.ts b/src/renderer/entities/wallet/lib/permission-utils.ts index 066c201c42..5739ee19e2 100644 --- a/src/renderer/entities/wallet/lib/permission-utils.ts +++ b/src/renderer/entities/wallet/lib/permission-utils.ts @@ -44,7 +44,6 @@ function canStake(wallet: Wallet): boolean { function canCreateMultisigTx(wallet: Wallet): boolean { if (walletUtils.isWatchOnly(wallet)) return false; if (walletUtils.isMultisig(wallet)) return false; - if (walletUtils.isFlexibleMultisig(wallet)) return false; if (walletUtils.isProxied(wallet)) { const isAnyProxy = accountUtils.isAnyProxyType(wallet.accounts[0]); const isNonTransfer = accountUtils.isNonTransferProxyType(wallet.accounts[0]); @@ -57,7 +56,6 @@ function canCreateMultisigTx(wallet: Wallet): boolean { function canApproveMultisigTx(wallet: Wallet): boolean { if (walletUtils.isWatchOnly(wallet)) return false; if (walletUtils.isMultisig(wallet)) return false; - if (walletUtils.isFlexibleMultisig(wallet)) return false; if (walletUtils.isProxied(wallet)) { return false; @@ -74,7 +72,6 @@ function canApproveMultisigTx(wallet: Wallet): boolean { function canRejectMultisigTx(wallet: Wallet): boolean { if (walletUtils.isWatchOnly(wallet)) return false; if (walletUtils.isMultisig(wallet)) return false; - if (walletUtils.isFlexibleMultisig(wallet)) return false; if (walletUtils.isProxied(wallet)) { return false; diff --git a/src/renderer/entities/wallet/lib/wallet-utils.ts b/src/renderer/entities/wallet/lib/wallet-utils.ts index fce609475f..b13d292b56 100644 --- a/src/renderer/entities/wallet/lib/wallet-utils.ts +++ b/src/renderer/entities/wallet/lib/wallet-utils.ts @@ -22,6 +22,7 @@ export const walletUtils = { isSingleShard, isMultisig, isFlexibleMultisig, + isRegularMultisig, isWatchOnly, isNovaWallet, isWalletConnect, @@ -54,12 +55,16 @@ function isSingleShard(wallet?: Wallet): wallet is SingleShardWallet { return wallet?.type === WalletType.SINGLE_PARITY_SIGNER; } -function isMultisig(wallet?: Wallet): wallet is MultisigWallet { +function isFlexibleMultisig(wallet?: Wallet): wallet is FlexibleMultisigWallet { + return wallet?.type === WalletType.FLEXIBLE_MULTISIG; +} + +function isRegularMultisig(wallet?: Wallet): wallet is FlexibleMultisigWallet { return wallet?.type === WalletType.MULTISIG; } -function isFlexibleMultisig(wallet?: Wallet): wallet is FlexibleMultisigWallet { - return wallet?.type === WalletType.FLEXIBLE_MULTISIG; +function isMultisig(wallet?: Wallet): wallet is MultisigWallet | FlexibleMultisigWallet { + return isFlexibleMultisig(wallet) || isRegularMultisig(wallet); } function isWatchOnly(wallet?: Wallet): wallet is WatchOnlyWallet { diff --git a/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts b/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts index 83ade49452..7f9c1ea5e5 100644 --- a/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts +++ b/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts @@ -29,7 +29,7 @@ import { nonNullable, toAccountId, toAddress, - transferableAmount, + withdrawableAmountBN, } from '@/shared/lib/utils'; import { createDepositCalculator, createFeeCalculator } from '@/shared/transactions'; import { balanceModel, balanceUtils } from '@/entities/balance'; @@ -218,7 +218,7 @@ const $isEnoughBalance = combine( return fee .add(multisigDeposit) .add(new BN(proxyDeposit)) - .lte(new BN(transferableAmount(balance))); + .lte(new BN(withdrawableAmountBN(balance))); }, ); @@ -413,8 +413,6 @@ sample({ name: name.trim(), accountId: multisigAccoutId!, threshold: threshold, - // TODO get proxy account - proxyAccountId: multisigAccoutId!, cryptoType: isEthereumChain ? CryptoType.ETHEREUM : CryptoType.SR25519, chainType: isEthereumChain ? ChainType.ETHEREUM : ChainType.SUBSTRATE, type: AccountType.FLEXIBLE_MULTISIG, diff --git a/src/renderer/features/operations/OperationsConfirm/Delegate/ui/Confirmation.tsx b/src/renderer/features/operations/OperationsConfirm/Delegate/ui/Confirmation.tsx index 95bb8e5179..b1ffe9137f 100644 --- a/src/renderer/features/operations/OperationsConfirm/Delegate/ui/Confirmation.tsx +++ b/src/renderer/features/operations/OperationsConfirm/Delegate/ui/Confirmation.tsx @@ -161,7 +161,7 @@ export const Confirmation = ({
- {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( - {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( - {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( - {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( - {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( - {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( - {accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( + {confirmStore.shards?.[0] && accountUtils.isMultisigAccount(confirmStore.shards[0]) && ( Boolean(account), fn: ({ wallet, wallets }, account): Record => { if (!wallet) return { isMultisig: false, isProxy: false }; - if (walletUtils.isMultisig(wallet)) return { isMultisig: true, isProxy: false }; + if (walletUtils.isRegularMultisig(wallet)) return { isMultisig: true, isProxy: false }; if (!walletUtils.isProxied(wallet)) return { isMultisig: false, isProxy: false }; const accountWallet = walletUtils.getWalletById(wallets, account!.walletId); return { - isMultisig: walletUtils.isMultisig(accountWallet), + isMultisig: walletUtils.isRegularMultisig(accountWallet), isProxy: true, }; }, diff --git a/src/renderer/features/proxy-add/model/form-model.ts b/src/renderer/features/proxy-add/model/form-model.ts index 9303029d93..137b5ce4b6 100644 --- a/src/renderer/features/proxy-add/model/form-model.ts +++ b/src/renderer/features/proxy-add/model/form-model.ts @@ -565,13 +565,13 @@ sample({ filter: (_, account) => Boolean(account), fn: ({ wallet, wallets }, account): Record => { if (!wallet) return { isMultisig: false, isProxy: false }; - if (walletUtils.isMultisig(wallet)) return { isMultisig: true, isProxy: false }; + if (walletUtils.isRegularMultisig(wallet)) return { isMultisig: true, isProxy: false }; if (!walletUtils.isProxied(wallet)) return { isMultisig: false, isProxy: false }; const accountWallet = walletUtils.getWalletById(wallets, account!.walletId); return { - isMultisig: walletUtils.isMultisig(accountWallet), + isMultisig: walletUtils.isRegularMultisig(accountWallet), isProxy: true, }; }, diff --git a/src/renderer/features/proxy-remove-pure/model/form-model.ts b/src/renderer/features/proxy-remove-pure/model/form-model.ts index e499e3297f..ddf93d4bbc 100644 --- a/src/renderer/features/proxy-remove-pure/model/form-model.ts +++ b/src/renderer/features/proxy-remove-pure/model/form-model.ts @@ -271,13 +271,13 @@ sample({ filter: (_, account) => Boolean(account), fn: ({ wallet, wallets }, account): Record => { if (!wallet) return { isMultisig: false, isProxy: false }; - if (walletUtils.isMultisig(wallet)) return { isMultisig: true, isProxy: false }; + if (walletUtils.isRegularMultisig(wallet)) return { isMultisig: true, isProxy: false }; if (!walletUtils.isProxied(wallet)) return { isMultisig: false, isProxy: false }; const accountWallet = walletUtils.getWalletById(wallets, account!.walletId); return { - isMultisig: walletUtils.isMultisig(accountWallet), + isMultisig: walletUtils.isRegularMultisig(accountWallet), isProxy: true, }; }, diff --git a/src/renderer/features/proxy-remove/model/form-model.ts b/src/renderer/features/proxy-remove/model/form-model.ts index 29728d7dba..2476c259d8 100644 --- a/src/renderer/features/proxy-remove/model/form-model.ts +++ b/src/renderer/features/proxy-remove/model/form-model.ts @@ -271,13 +271,13 @@ sample({ filter: (_, account) => Boolean(account), fn: ({ wallet, wallets }, account): Record => { if (!wallet) return { isMultisig: false, isProxy: false }; - if (walletUtils.isMultisig(wallet)) return { isMultisig: true, isProxy: false }; + if (walletUtils.isRegularMultisig(wallet)) return { isMultisig: true, isProxy: false }; if (!walletUtils.isProxied(wallet)) return { isMultisig: false, isProxy: false }; const accountWallet = walletUtils.getWalletById(wallets, account!.walletId); return { - isMultisig: walletUtils.isMultisig(accountWallet), + isMultisig: walletUtils.isRegularMultisig(accountWallet), isProxy: true, }; }, diff --git a/src/renderer/features/wallet-details/ui/components/WalletDetails.tsx b/src/renderer/features/wallet-details/ui/components/WalletDetails.tsx index 90aab6140b..4abcaa3ae7 100644 --- a/src/renderer/features/wallet-details/ui/components/WalletDetails.tsx +++ b/src/renderer/features/wallet-details/ui/components/WalletDetails.tsx @@ -37,6 +37,7 @@ export const WalletDetails = ({ isOpen, wallet, onClose }: Props) => { return ; } + // TODO: Separate wallet details for regular and flexible multisig if (walletUtils.isMultisig(wallet)) { return ( { diff --git a/src/renderer/pages/Operations/components/OperationCardDetails.tsx b/src/renderer/pages/Operations/components/OperationCardDetails.tsx index 371893b99c..9626cde68e 100644 --- a/src/renderer/pages/Operations/components/OperationCardDetails.tsx +++ b/src/renderer/pages/Operations/components/OperationCardDetails.tsx @@ -5,6 +5,8 @@ import { Trans } from 'react-i18next'; import { chainsService } from '@/shared/api/network'; import { type Address, + type FlexibleMultisigAccount, + type FlexibleMultisigTransaction, type MultisigAccount, type MultisigTransaction, type Transaction, @@ -51,8 +53,8 @@ import { } from '../common/utils'; type Props = { - tx: MultisigTransaction; - account?: MultisigAccount; + tx: MultisigTransaction | FlexibleMultisigTransaction; + account?: MultisigAccount | FlexibleMultisigAccount; extendedChain?: ExtendedChain; }; diff --git a/src/renderer/pages/Operations/components/OperationFullInfo.tsx b/src/renderer/pages/Operations/components/OperationFullInfo.tsx index 3f8e773f67..8601e3e076 100644 --- a/src/renderer/pages/Operations/components/OperationFullInfo.tsx +++ b/src/renderer/pages/Operations/components/OperationFullInfo.tsx @@ -1,8 +1,8 @@ import { useUnit } from 'effector-react'; import { useMultisigChainContext } from '@/app/providers'; -import { type MultisigTransactionDS } from '@/shared/api/storage'; -import { type CallData, type MultisigAccount } from '@/shared/core'; +import { type FlexibleMultisigTransactionDS, type MultisigTransactionDS } from '@/shared/api/storage'; +import { type CallData, type FlexibleMultisigAccount, type MultisigAccount } from '@/shared/core'; import { useI18n } from '@/shared/i18n'; import { useToggle } from '@/shared/lib/hooks'; import { Button, Icon, InfoLink, SmallTitleText } from '@/shared/ui'; @@ -18,8 +18,8 @@ import CallDataModal from './modals/CallDataModal'; import RejectTxModal from './modals/RejectTx'; type Props = { - tx: MultisigTransactionDS; - account?: MultisigAccount; + tx: MultisigTransactionDS | FlexibleMultisigTransactionDS; + account?: MultisigAccount | FlexibleMultisigAccount; }; export const OperationFullInfo = ({ tx, account }: Props) => { diff --git a/src/renderer/pages/Operations/components/OperationSignatories.tsx b/src/renderer/pages/Operations/components/OperationSignatories.tsx index 358e79e74f..c86707844d 100644 --- a/src/renderer/pages/Operations/components/OperationSignatories.tsx +++ b/src/renderer/pages/Operations/components/OperationSignatories.tsx @@ -3,6 +3,8 @@ import { useEffect, useState } from 'react'; import { type AccountId, + type FlexibleMultisigAccount, + type FlexibleMultisigTransaction, type MultisigAccount, type MultisigEvent, type MultisigTransaction, @@ -26,9 +28,9 @@ import LogModal from './LogModal'; type WalletSignatory = Signatory & { wallet: Wallet }; type Props = { - tx: MultisigTransaction; + tx: MultisigTransaction | FlexibleMultisigTransaction; connection: ExtendedChain; - account: MultisigAccount; + account: MultisigAccount | FlexibleMultisigAccount; }; export const OperationSignatories = ({ tx, connection, account }: Props) => { diff --git a/src/renderer/pages/Operations/components/modals/ApproveTx.tsx b/src/renderer/pages/Operations/components/modals/ApproveTx.tsx index 9de0b2e7c1..2b1bdbbf28 100644 --- a/src/renderer/pages/Operations/components/modals/ApproveTx.tsx +++ b/src/renderer/pages/Operations/components/modals/ApproveTx.tsx @@ -3,10 +3,11 @@ import { BN } from '@polkadot/util'; import { useUnit } from 'effector-react'; import { useEffect, useState } from 'react'; -import { type MultisigTransactionDS } from '@/shared/api/storage'; +import { type FlexibleMultisigTransactionDS, type MultisigTransactionDS } from '@/shared/api/storage'; import { type Account, type Address, + type FlexibleMultisigAccount, type HexString, type MultisigAccount, type Timepoint, @@ -41,8 +42,8 @@ import { Submit } from '../ActionSteps/Submit'; import { SignatorySelectModal } from './SignatorySelectModal'; type Props = { - tx: MultisigTransactionDS; - account: MultisigAccount; + tx: MultisigTransactionDS | FlexibleMultisigTransactionDS; + account: MultisigAccount | FlexibleMultisigAccount; connection: ExtendedChain; children: React.ReactNode; }; diff --git a/src/renderer/pages/Operations/components/modals/RejectTx.tsx b/src/renderer/pages/Operations/components/modals/RejectTx.tsx index 10900d9f67..c0c77544bd 100644 --- a/src/renderer/pages/Operations/components/modals/RejectTx.tsx +++ b/src/renderer/pages/Operations/components/modals/RejectTx.tsx @@ -3,8 +3,15 @@ import { useUnit } from 'effector-react'; import { sortBy } from 'lodash'; import { useEffect, useState } from 'react'; -import { type MultisigTransactionDS } from '@/shared/api/storage'; -import { type Account, type Address, type HexString, type MultisigAccount, type Transaction } from '@/shared/core'; +import { type FlexibleMultisigTransactionDS, type MultisigTransactionDS } from '@/shared/api/storage'; +import { + type Account, + type Address, + type FlexibleMultisigAccount, + type HexString, + type MultisigAccount, + type Transaction, +} from '@/shared/core'; import { TransactionType } from '@/shared/core'; import { useI18n } from '@/shared/i18n'; import { useToggle } from '@/shared/lib/hooks'; @@ -29,8 +36,8 @@ import { Confirmation } from '../ActionSteps/Confirmation'; import { Submit } from '../ActionSteps/Submit'; type Props = { - tx: MultisigTransactionDS; - account: MultisigAccount; + tx: MultisigTransactionDS | FlexibleMultisigTransactionDS; + account: MultisigAccount | FlexibleMultisigAccount; connection: ExtendedChain; children: React.ReactNode; }; diff --git a/src/renderer/processes/multisigs/model/multisigs-model.ts b/src/renderer/processes/multisigs/model/multisigs-model.ts index 969c4797c2..c18cf68473 100644 --- a/src/renderer/processes/multisigs/model/multisigs-model.ts +++ b/src/renderer/processes/multisigs/model/multisigs-model.ts @@ -213,7 +213,7 @@ sample({ clock: walletModel.events.walletCreatedDone, filter: ({ wallet }) => wallet.type === WalletType.MULTISIG, fn: ({ accounts }) => { - return accounts.filter(accountUtils.isMultisigAccount).map>((account) => { + return accounts.filter(accountUtils.isRegularMultisigAccount).map>((account) => { return { read: false, type: NotificationType.MULTISIG_CREATED, @@ -241,7 +241,6 @@ sample({ dateCreated: Date.now(), multisigAccountId: account.accountId, multisigAccountName: account.name, - proxyAccountId: account.proxyAccountId, chainId: account.chainId, signatories: account.signatories.map((signatory) => signatory.accountId), threshold: account.threshold, diff --git a/src/renderer/shared/api/storage/lib/types.ts b/src/renderer/shared/api/storage/lib/types.ts index 48fe2424bc..5c8ec9d77b 100644 --- a/src/renderer/shared/api/storage/lib/types.ts +++ b/src/renderer/shared/api/storage/lib/types.ts @@ -11,6 +11,7 @@ import { type ChainMetadata, type Connection, type Contact, + type FlexibleMultisigTransaction, type MultisigEvent, type MultisigTransaction, type MultisigTransactionKey, @@ -72,6 +73,7 @@ export type ID = string; type WithID> = { id?: ID } & T; export type MultisigTransactionDS = WithID; +export type FlexibleMultisigTransactionDS = WithID; export type MultisigEventDS = WithID; export type TWallet = Table, Wallet['id']>; diff --git a/src/renderer/shared/core/index.ts b/src/renderer/shared/core/index.ts index 151c888aec..d9c5f06109 100644 --- a/src/renderer/shared/core/index.ts +++ b/src/renderer/shared/core/index.ts @@ -88,6 +88,7 @@ export type { DecodedTransaction, MultisigEvent, MultisigTransaction, + FlexibleMultisigTransaction, MultisigTransactionKey, TxWrapper, TxWrappers_OLD, diff --git a/src/renderer/shared/core/types/account.ts b/src/renderer/shared/core/types/account.ts index 04229c3b4d..f6535f50b7 100644 --- a/src/renderer/shared/core/types/account.ts +++ b/src/renderer/shared/core/types/account.ts @@ -52,11 +52,11 @@ export type MultisigAccount = GenericAccount & { export type FlexibleMultisigAccount = GenericAccount & { type: AccountType.FLEXIBLE_MULTISIG; - proxyAccountId: AccountId; signatories: Signatory[]; threshold: MultisigThreshold; chainId: ChainId; cryptoType: CryptoType; + proxyAccountId?: AccountId; // we have accountId only after proxy is created }; export type WcAccount = GenericAccount & { diff --git a/src/renderer/shared/core/types/notification.ts b/src/renderer/shared/core/types/notification.ts index 799201df27..3c0c855322 100644 --- a/src/renderer/shared/core/types/notification.ts +++ b/src/renderer/shared/core/types/notification.ts @@ -36,7 +36,6 @@ export type FlexibleMultisigCreated = MultisigBaseNotification & { walletId: number; signatories: AccountId[]; threshold: number; - proxyAccountId: AccountId; multisigAccountName: string; chainId: ChainId; }; diff --git a/src/renderer/shared/core/types/transaction.ts b/src/renderer/shared/core/types/transaction.ts index cfc08edd3a..7c246bf69b 100644 --- a/src/renderer/shared/core/types/transaction.ts +++ b/src/renderer/shared/core/types/transaction.ts @@ -113,6 +113,10 @@ export type MultisigTransaction = { transaction?: Transaction | DecodedTransaction; }; +export type FlexibleMultisigTransaction = MultisigTransaction & { + proxiedAccountId: AccountId; +}; + export type MultisigTransactionKey = Pick< MultisigTransaction, 'accountId' | 'callHash' | 'chainId' | 'indexCreated' | 'blockCreated' diff --git a/src/renderer/widgets/UnlockModal/ui/UnlockConfirmation.tsx b/src/renderer/widgets/UnlockModal/ui/UnlockConfirmation.tsx index fe4ea5300e..07029ce924 100644 --- a/src/renderer/widgets/UnlockModal/ui/UnlockConfirmation.tsx +++ b/src/renderer/widgets/UnlockModal/ui/UnlockConfirmation.tsx @@ -108,7 +108,7 @@ export const UnlockConfirmation = ({ id = 0, hideSignButton, secondaryActionButt
- {accountUtils.isMultisigAccount(shards[0]) && ( + {shards?.[0] && accountUtils.isMultisigAccount(shards[0]) && ( Date: Thu, 21 Nov 2024 15:30:54 +0700 Subject: [PATCH 2/4] feat: add existential deposit --- .../components/MultisigFees.tsx | 3 +- .../model/flexible-multisig-create.ts | 33 ++++++++++++------- .../api/balances/service/balanceService.ts | 14 +++++++- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/renderer/features/flexible-multisig-create/components/MultisigFees.tsx b/src/renderer/features/flexible-multisig-create/components/MultisigFees.tsx index 4b145bec9a..d53c5d4d4d 100644 --- a/src/renderer/features/flexible-multisig-create/components/MultisigFees.tsx +++ b/src/renderer/features/flexible-multisig-create/components/MultisigFees.tsx @@ -1,4 +1,3 @@ -import { BN } from '@polkadot/util'; import { useUnit } from 'effector-react'; import { memo } from 'react'; @@ -22,7 +21,7 @@ export const MultisigFees = memo(({ asset }: Props) => { const proxyDeposit = useUnit(flexibleMultisigModel.$proxyDeposit); const isLoading = useUnit(flexibleMultisigModel.$isLoading); - const totalFee = multisigDeposit.add(fee).add(new BN(proxyDeposit)); + const totalFee = multisigDeposit.add(fee).add(proxyDeposit); if (isLoading) { return ( diff --git a/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts b/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts index 7f9c1ea5e5..852743c5db 100644 --- a/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts +++ b/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts @@ -1,13 +1,15 @@ import { type ApiPromise } from '@polkadot/api'; -import { BN } from '@polkadot/util'; +import { BN, BN_ZERO } from '@polkadot/util'; import { combine, createEffect, createEvent, createStore, restore, sample } from 'effector'; import sortBy from 'lodash/sortBy'; import { delay, or, spread } from 'patronum'; +import { balanceService } from '@/shared/api/balances'; import { proxyService } from '@/shared/api/proxy'; import { type Account, AccountType, + type Asset, type Chain, ChainType, type Contact, @@ -24,7 +26,6 @@ import { SS58_DEFAULT_PREFIX, Step, TEST_ACCOUNTS, - ZERO_BALANCE, isStep, nonNullable, toAccountId, @@ -76,7 +77,7 @@ const walletCreated = createEvent<{ const $step = restore(stepChanged, Step.NAME_NETWORK).reset(flowFinished); -const $proxyDeposit = createStore(ZERO_BALANCE).reset(flowFinished); +const $proxyDeposit = createStore(BN_ZERO).reset(flowFinished); const $error = createStore('').reset(flowFinished); const $wrappedTx = createStore(null).reset(flowFinished); const $coreTx = createStore(null).reset(flowFinished); @@ -119,7 +120,7 @@ const $transaction = combine( proxyDeposit: $proxyDeposit, }, ({ api, form, chain, isConnected, signatories, signer, proxyDeposit, multisigAccountId }) => { - if (!isConnected || !chain || !api || !multisigAccountId || !form.threshold || !proxyDeposit || !signer) { + if (!isConnected || !chain || !api || !multisigAccountId || !form.threshold || !signer) { return null; } @@ -132,7 +133,7 @@ const $transaction = combine( signatories: signatoriesWrapped, multisigAccountId, threshold: form.threshold, - proxyDeposit, + proxyDeposit: proxyDeposit.toString(), }); }, ); @@ -181,18 +182,28 @@ const { $deposit: $multisigDeposit, $pending: $pendingDeposit } = createDepositC $threshold: formModel.$createMultisigForm.fields.threshold.$value, }); -const getProxyDepositFx = createEffect((api: ApiPromise): string => { - return proxyService.getProxyDeposit(api, '0', 1); +type GetDepositParams = { + api: ApiPromise; + asset: Asset; +}; + +const getDepositFx = createEffect(async ({ api, asset }: GetDepositParams): Promise => { + const minDeposit = await balanceService.getExistentialDeposit(api, asset); + const proxyDeposit = new BN(proxyService.getProxyDeposit(api, '0', 1)); + + return BN.max(minDeposit, proxyDeposit); }); sample({ clock: $api, - filter: nonNullable, - target: getProxyDepositFx, + source: formModel.$chain, + filter: (chain, api) => nonNullable(api) && nonNullable(chain) && nonNullable(chain.assets?.[0]), + fn: (chain, api) => ({ api: api!, asset: chain!.assets[0] }), + target: getDepositFx, }); sample({ - clock: getProxyDepositFx.doneData, + clock: getDepositFx.doneData, target: $proxyDeposit, }); @@ -508,7 +519,7 @@ export const flexibleMultisigModel = { $fee, $proxyDeposit, $multisigDeposit, - $isLoading: or($pendingFee, $pendingDeposit, getProxyDepositFx.pending), + $isLoading: or($pendingFee, $pendingDeposit, getDepositFx.pending), $isEnoughBalance, events: { diff --git a/src/renderer/shared/api/balances/service/balanceService.ts b/src/renderer/shared/api/balances/service/balanceService.ts index b248d8538b..820303dea7 100644 --- a/src/renderer/shared/api/balances/service/balanceService.ts +++ b/src/renderer/shared/api/balances/service/balanceService.ts @@ -4,7 +4,7 @@ import { type Vec } from '@polkadot/types'; import { type AccountData, type Balance as ChainBalance } from '@polkadot/types/interfaces'; import { type PalletBalancesBalanceLock } from '@polkadot/types/lookup'; import { type Codec } from '@polkadot/types/types'; -import { type BN, BN_ZERO, hexToU8a } from '@polkadot/util'; +import { BN, BN_ZERO, hexToU8a } from '@polkadot/util'; import noop from 'lodash/noop'; import uniq from 'lodash/uniq'; @@ -25,6 +25,7 @@ type NoIdBalance = Omit; export const balanceService = { subscribeBalances, subscribeLockBalances, + getExistentialDeposit, }; /** @@ -308,3 +309,14 @@ function subscribeLockOrmlAssetChange( callback(newLocks); }); } + +async function getExistentialDeposit(api: ApiPromise, asset: Asset): Promise { + switch (asset.type) { + case AssetType.NATIVE: + return api.consts.balances.existentialDeposit.toBn(); + case AssetType.STATEMINE: + return await api.query.assets.asset(asset.assetId).then((balance) => balance.value.minBalance.toBn()); + case AssetType.ORML: + return new BN((asset.typeExtras as OrmlExtras).existentialDeposit); + } +} From 9373dbbc72f6e23f76c886ada6472874d7adeae6 Mon Sep 17 00:00:00 2001 From: sokolova-an Date: Thu, 21 Nov 2024 19:03:40 +0700 Subject: [PATCH 3/4] chore: typo --- .../model/flexible-multisig-create.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts b/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts index 852743c5db..1607fd20e1 100644 --- a/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts +++ b/src/renderer/features/flexible-multisig-create/model/flexible-multisig-create.ts @@ -187,7 +187,7 @@ type GetDepositParams = { asset: Asset; }; -const getDepositFx = createEffect(async ({ api, asset }: GetDepositParams): Promise => { +const getProxyDepositFx = createEffect(async ({ api, asset }: GetDepositParams): Promise => { const minDeposit = await balanceService.getExistentialDeposit(api, asset); const proxyDeposit = new BN(proxyService.getProxyDeposit(api, '0', 1)); @@ -199,11 +199,11 @@ sample({ source: formModel.$chain, filter: (chain, api) => nonNullable(api) && nonNullable(chain) && nonNullable(chain.assets?.[0]), fn: (chain, api) => ({ api: api!, asset: chain!.assets[0] }), - target: getDepositFx, + target: getProxyDepositFx, }); sample({ - clock: getDepositFx.doneData, + clock: getProxyDepositFx.doneData, target: $proxyDeposit, }); @@ -519,7 +519,7 @@ export const flexibleMultisigModel = { $fee, $proxyDeposit, $multisigDeposit, - $isLoading: or($pendingFee, $pendingDeposit, getDepositFx.pending), + $isLoading: or($pendingFee, $pendingDeposit, getProxyDepositFx.pending), $isEnoughBalance, events: { From ca94d73cebde8983fc3486ee50d69398dcf65ef5 Mon Sep 17 00:00:00 2001 From: sokolova-an Date: Thu, 21 Nov 2024 19:27:37 +0700 Subject: [PATCH 4/4] chore: fix --- .../shared/api/balances/service/balanceService.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/renderer/shared/api/balances/service/balanceService.ts b/src/renderer/shared/api/balances/service/balanceService.ts index 820303dea7..fd408f1cbf 100644 --- a/src/renderer/shared/api/balances/service/balanceService.ts +++ b/src/renderer/shared/api/balances/service/balanceService.ts @@ -312,11 +312,14 @@ function subscribeLockOrmlAssetChange( async function getExistentialDeposit(api: ApiPromise, asset: Asset): Promise { switch (asset.type) { - case AssetType.NATIVE: + case AssetType.NATIVE: { return api.consts.balances.existentialDeposit.toBn(); - case AssetType.STATEMINE: + } + case AssetType.STATEMINE: { return await api.query.assets.asset(asset.assetId).then((balance) => balance.value.minBalance.toBn()); - case AssetType.ORML: + } + case AssetType.ORML: { return new BN((asset.typeExtras as OrmlExtras).existentialDeposit); + } } }