Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add flexible multisig wallet and account types #2636

Merged
merged 2 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/renderer/entities/wallet/lib/permission-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ 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]);
Expand All @@ -56,6 +57,7 @@ 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;
Expand All @@ -72,6 +74,7 @@ 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;

Expand Down
11 changes: 11 additions & 0 deletions src/renderer/entities/wallet/lib/wallet-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
type Account,
type FlexibleMultisigWallet,
type ID,
type MultiShardWallet,
type MultisigWallet,
Expand All @@ -20,6 +21,7 @@ export const walletUtils = {
isMultiShard,
isSingleShard,
isMultisig,
isFlexibleMultisig,
isWatchOnly,
isNovaWallet,
isWalletConnect,
Expand All @@ -33,6 +35,7 @@ export const walletUtils = {

getAccountBy,
getAccountsBy,
getAllAccounts,
getWalletFilteredAccounts,
getWalletsFilteredAccounts,
};
Expand All @@ -55,6 +58,10 @@ function isMultisig(wallet?: Wallet): wallet is MultisigWallet {
return wallet?.type === WalletType.MULTISIG;
}

function isFlexibleMultisig(wallet?: Wallet): wallet is FlexibleMultisigWallet {
return wallet?.type === WalletType.FLEXIBLE_MULTISIG;
}

function isWatchOnly(wallet?: Wallet): wallet is WatchOnlyWallet {
return wallet?.type === WalletType.WATCH_ONLY;
}
Expand Down Expand Up @@ -111,6 +118,10 @@ function getAccountsBy(wallets: Wallet[], accountFn: (account: Account, wallet:
}, []);
}

function getAllAccounts(wallets: Wallet[]): Account[] {
return wallets.reduce<Account[]>((acc, wallet) => acc.concat(wallet.accounts), []);
}

function getAccountBy(wallets: Wallet[], accountFn: (account: Account, wallet: Wallet) => boolean): Account | null {
for (const wallet of wallets) {
const account = wallet.accounts.find((account) => accountFn(account, wallet));
Expand Down
5 changes: 4 additions & 1 deletion src/renderer/entities/wallet/ui/Cards/WalletCardMd.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ export const WalletCardMd = ({ wallet, description, prefix, hideIcon, className,
className,
)}
>
<button className="flex w-full items-center gap-x-2 rounded px-2 py-1.5" onClick={handleClick(onClick)}>
<button
className={cnTw('flex w-full items-center gap-x-2 rounded px-2 py-1.5', { 'pe-6': onInfoClick })}
onClick={handleClick(onClick)}
>
{prefix}

{!hideIcon && <WalletIcon type={wallet.type} size={20} />}
Expand Down
1 change: 1 addition & 0 deletions src/renderer/entities/wallet/ui/WalletIcon/WalletIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const WalletIconNames: Record<WalletType, IconNames> = {
[WalletType.SINGLE_PARITY_SIGNER]: 'vaultBackground',
[WalletType.WATCH_ONLY]: 'watchOnlyBackground',
[WalletType.MULTISIG]: 'multisigBackground',
[WalletType.FLEXIBLE_MULTISIG]: 'flexibleMultisigBackground',
[WalletType.MULTISHARD_PARITY_SIGNER]: 'vaultBackground',
[WalletType.WALLET_CONNECT]: 'walletConnectBackground',
[WalletType.NOVA_WALLET]: 'novaWalletBackground',
Expand Down
1 change: 1 addition & 0 deletions src/renderer/features/emptyList/ui/EmptyAccountMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useI18n } from '@/shared/i18n';
const Messages: Record<WalletType, string> = {
[WalletType.POLKADOT_VAULT]: 'emptyState.createOrImportAccount',
[WalletType.MULTISIG]: 'emptyState.createMultisig',
[WalletType.FLEXIBLE_MULTISIG]: 'emptyState.createFlexibleMultisig',
[WalletType.MULTISHARD_PARITY_SIGNER]: 'emptyState.createAccount',
[WalletType.NOVA_WALLET]: 'emptyState.createAccount',
[WalletType.PROXIED]: 'emptyState.createAccount',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ type CreateWalletParams = {
name: string;
threshold: number;
signatories: Signatory[];
chainId: ChainId | null;
chainId: ChainId;
isEthereumChain: boolean;
};

Expand All @@ -425,6 +425,7 @@ const createWalletFx = createEffect(
const accountIds = signatories.map((s) => s.accountId);
const accountId = accountUtils.getMultisigAccountId(accountIds, threshold, cryptoType);

// TODO implement flexible multisig creation
walletModel.events.multisigCreated({
wallet: {
name,
Expand All @@ -434,11 +435,10 @@ const createWalletFx = createEffect(
accounts: [
{
signatories,
chainId: chainId || undefined,
chainId,
name: name.trim(),
accountId: accountId,
threshold: threshold,
creatorAccountId: accountId,
cryptoType: isEthereumChain ? CryptoType.ETHEREUM : CryptoType.SR25519,
chainType: isEthereumChain ? ChainType.ETHEREUM : ChainType.SUBSTRATE,
type: AccountType.MULTISIG,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function getWalletByGroups(wallets: Wallet[], query = ''): Record<WalletFamily,
const accumulator: Record<WalletFamily, Wallet[]> = {
[WalletType.POLKADOT_VAULT]: [],
[WalletType.MULTISIG]: [],
[WalletType.FLEXIBLE_MULTISIG]: [],
[WalletType.NOVA_WALLET]: [],
[WalletType.WALLET_CONNECT]: [],
[WalletType.WATCH_ONLY]: [],
Expand All @@ -21,6 +22,7 @@ function getWalletByGroups(wallets: Wallet[], query = ''): Record<WalletFamily,

if (walletUtils.isPolkadotVaultGroup(wallet)) groupIndex = WalletType.POLKADOT_VAULT;
if (walletUtils.isMultisig(wallet)) groupIndex = WalletType.MULTISIG;
if (walletUtils.isFlexibleMultisig(wallet)) groupIndex = WalletType.FLEXIBLE_MULTISIG;
if (walletUtils.isWatchOnly(wallet)) groupIndex = WalletType.WATCH_ONLY;
if (walletUtils.isWalletConnect(wallet)) groupIndex = WalletType.WALLET_CONNECT;
if (walletUtils.isNovaWallet(wallet)) groupIndex = WalletType.NOVA_WALLET;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const {
export const GROUP_LABELS: Record<WalletFamily, string> = {
[WalletType.POLKADOT_VAULT]: 'wallets.paritySignerLabel',
[WalletType.MULTISIG]: 'wallets.multisigLabel',
[WalletType.FLEXIBLE_MULTISIG]: 'wallets.flexibleMultisigLabel',
[WalletType.WALLET_CONNECT]: 'wallets.walletConnectLabel',
[WalletType.NOVA_WALLET]: 'wallets.novaWalletLabel',
[WalletType.WATCH_ONLY]: 'wallets.watchOnlyLabel',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('wallet-select-model', () => {
const emptyGroups: Record<WalletFamily, Wallet[]> = {
[WalletType.POLKADOT_VAULT]: [],
[WalletType.MULTISIG]: [],
[WalletType.FLEXIBLE_MULTISIG]: [],
[WalletType.NOVA_WALLET]: [],
[WalletType.WALLET_CONNECT]: [],
[WalletType.WATCH_ONLY]: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ function getWalletByGroups(wallets: Wallet[], query = ''): Record<WalletFamily,
const accumulator: Record<WalletFamily, Wallet[]> = {
[WalletType.POLKADOT_VAULT]: [],
[WalletType.MULTISIG]: [],
[WalletType.FLEXIBLE_MULTISIG]: [],
[WalletType.NOVA_WALLET]: [],
[WalletType.WALLET_CONNECT]: [],
[WalletType.WATCH_ONLY]: [],
Expand All @@ -21,6 +22,7 @@ function getWalletByGroups(wallets: Wallet[], query = ''): Record<WalletFamily,

if (walletUtils.isPolkadotVaultGroup(wallet)) groupIndex = WalletType.POLKADOT_VAULT;
if (walletUtils.isMultisig(wallet)) groupIndex = WalletType.MULTISIG;
if (walletUtils.isFlexibleMultisig(wallet)) groupIndex = WalletType.FLEXIBLE_MULTISIG;
if (walletUtils.isWatchOnly(wallet)) groupIndex = WalletType.WATCH_ONLY;
if (walletUtils.isWalletConnect(wallet)) groupIndex = WalletType.WALLET_CONNECT;
if (walletUtils.isNovaWallet(wallet)) groupIndex = WalletType.NOVA_WALLET;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/renderer/shared/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type {
SingleShardWallet,
MultiShardWallet,
MultisigWallet,
FlexibleMultisigWallet,
WatchOnlyWallet,
WalletConnectWallet,
NovaWalletWallet,
Expand All @@ -30,6 +31,7 @@ export type {
BaseAccount,
ChainAccount,
MultisigAccount,
FlexibleMultisigAccount,
WcAccount,
ProxiedAccount,
ShardAccount,
Expand Down
22 changes: 19 additions & 3 deletions src/renderer/shared/core/types/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,17 @@ export type MultisigAccount = GenericAccount & {
type: AccountType.MULTISIG;
signatories: Signatory[];
threshold: MultisigThreshold;
chainId?: ChainId;
chainId: ChainId;
cryptoType: CryptoType;
};

export type FlexibleMultisigAccount = GenericAccount & {
type: AccountType.FLEXIBLE_MULTISIG;
proxyAccountId: AccountId;
signatories: Signatory[];
threshold: MultisigThreshold;
chainId: ChainId;
cryptoType: CryptoType;
creatorAccountId: AccountId;
};

export type WcAccount = GenericAccount & {
Expand All @@ -68,7 +76,14 @@ export type ProxiedAccount = GenericAccount & {
cryptoType: CryptoType;
};

export type Account = BaseAccount | ChainAccount | ShardAccount | MultisigAccount | WcAccount | ProxiedAccount;
export type Account =
| BaseAccount
| ChainAccount
| ShardAccount
| MultisigAccount
| WcAccount
| ProxiedAccount
| FlexibleMultisigAccount;

export type DraftAccount<T extends Account> = Omit<NoID<T>, 'accountId' | 'walletId' | 'baseId'>;

Expand All @@ -77,6 +92,7 @@ export const enum AccountType {
CHAIN = 'chain',
SHARD = 'shard',
MULTISIG = 'multisig',
FLEXIBLE_MULTISIG = 'flexible_multisig',
WALLET_CONNECT = 'wallet_connect',
PROXIED = 'proxied',
}
Expand Down
9 changes: 9 additions & 0 deletions src/renderer/shared/core/types/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
type Account,
type BaseAccount,
type ChainAccount,
type FlexibleMultisigAccount,
type MultisigAccount,
type ProxiedAccount,
type ShardAccount,
Expand Down Expand Up @@ -45,6 +46,12 @@ export interface MultisigWallet extends Wallet {
accounts: MultisigAccount[];
}

// TODO: try to move signatories data out of account
export interface FlexibleMultisigWallet extends Wallet {
type: WalletType.FLEXIBLE_MULTISIG;
accounts: FlexibleMultisigAccount[];
}

export interface ProxiedWallet extends Wallet {
type: WalletType.PROXIED;
accounts: ProxiedAccount[];
Expand All @@ -68,6 +75,7 @@ export const enum WalletType {
WATCH_ONLY = 'wallet_wo',
POLKADOT_VAULT = 'wallet_pv',
MULTISIG = 'wallet_ms',
FLEXIBLE_MULTISIG = 'wallet_fxms',
WALLET_CONNECT = 'wallet_wc',
NOVA_WALLET = 'wallet_nw',
PROXIED = 'wallet_pxd',
Expand All @@ -87,6 +95,7 @@ export type SignableWalletFamily =
export type WalletFamily =
| WalletType.POLKADOT_VAULT
| WalletType.MULTISIG
| WalletType.FLEXIBLE_MULTISIG
| WalletType.WATCH_ONLY
| WalletType.WALLET_CONNECT
| WalletType.NOVA_WALLET
Expand Down
5 changes: 4 additions & 1 deletion src/renderer/shared/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@
"addNewAccountButton": "Add new account",
"createAccount": "Create a new account",
"createMultisig": "Create a new multisig wallet",
"createFlexibleMultisig": "Create a new flexible multisig wallet",
"createOrImportAccount": "Create a new account or import an existing one"
},
"fallbackScreen": {
Expand Down Expand Up @@ -1157,7 +1158,8 @@
"identityJudgement": "Judgement operations",
"nominationPools": "Nominations operations",
"nonTransfer": "All, except transfer operations",
"staking": "Staking operations"
"staking": "Staking operations",
"unknown": "Unknown operations"
},
"operations": {
"any": "all operations",
Expand Down Expand Up @@ -1703,6 +1705,7 @@
"disconnectedLabel": "Disconnected",
"multishardLabel": "Multishard",
"multisigLabel": "Multisig",
"flexibleMultisigLabel": "Flexible Multisig",
"novaWalletLabel": "Nova Wallet",
"paritySignerLabel": "Polkadot Vault",
"proxiedLabel": "Delegated to you (Proxied)",
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/shared/ui/Icon/data/walletType.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* eslint-disable import-x/max-dependencies */

import FlexibleMultisigBackgroundImg, {
ReactComponent as FlexibleMultisigBackgroundSvg,
} from '@/shared/assets/images/walletTypes/flexibleMultisigBackground.svg';
import LedgerOnboardingImg, {
ReactComponent as LedgerOnboardingSvg,
} from '@/shared/assets/images/walletTypes/ledgerOnboarding.svg';
Expand Down Expand Up @@ -44,6 +47,7 @@ const WalletTypeImages = {
watchOnlyBackground: { svg: WatchOnlyBackgroundSvg, img: WatchOnlyBackgroundImg },
watchOnlyOnboarding: { svg: WatchOnlyOnboardingSvg, img: WatchOnlyOnboardingImg },
multisigBackground: { svg: MultisigBackgroundSvg, img: MultisigBackgroundImg },
flexibleMultisigBackground: { svg: FlexibleMultisigBackgroundSvg, img: FlexibleMultisigBackgroundImg },
vault: { svg: VaultSvg, img: VaultImg },
vaultBackground: { svg: VaultBackgroundSvg, img: VaultBackgroundImg },
vaultOnboarding: { svg: VaultOnboardingSvg, img: VaultOnboardingImg },
Expand Down
5 changes: 2 additions & 3 deletions src/renderer/widgets/CreateWallet/model/flow-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ type CreateWalletParams = {
name: string;
threshold: number;
signatories: Signatory[];
chainId: ChainId | null;
chainId: ChainId;
isEthereumChain: boolean;
};

Expand All @@ -212,11 +212,10 @@ const createWalletFx = createEffect(
accounts: [
{
signatories,
chainId: chainId || undefined,
chainId,
name: name.trim(),
accountId: accountId,
threshold: threshold,
creatorAccountId: accountId,
cryptoType: isEthereumChain ? CryptoType.ETHEREUM : CryptoType.SR25519,
chainType: isEthereumChain ? ChainType.ETHEREUM : ChainType.SUBSTRATE,
type: AccountType.MULTISIG,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const WalletModals: Record<WalletFamily, (props: ModalProps) => JSX.Element | nu
[WalletType.MULTISIG]: (props) => <SelectMultisigWalletType isOpen {...props} />,
[WalletType.WALLET_CONNECT]: (props) => <WalletConnect isOpen {...props} />,
[WalletType.NOVA_WALLET]: (props) => <NovaWallet isOpen {...props} />,
[WalletType.FLEXIBLE_MULTISIG]: () => null,
[WalletType.PROXIED]: () => null,
};

Expand Down
Loading