diff --git a/package.json b/package.json index 95408643eb..fb2b3a5d60 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "@ariakit/react": "0.4.14", "@headlessui/react": "^1.7.17", "@polkadot/api": "15.3.1", - "@polkadot/extension-dapp": "0.58.1", "@polkadot/keyring": "13.3.1", "@polkadot/react-identicon": "3.11.3", "@polkadot/rpc-provider": "15.3.1", @@ -97,6 +96,7 @@ "@substrate/connect": "2.1.1", "@substrate/txwrapper-orml": "7.5.3", "@substrate/txwrapper-polkadot": "7.5.3", + "@talismn/connect-wallets": "1.2.8", "@walletconnect/core": "2.17.3", "@walletconnect/sign-client": "2.17.3", "@walletconnect/types": "2.17.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e51269a37..957cf975df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,6 @@ importers: '@polkadot/api': specifier: 15.3.1 version: 15.3.1 - '@polkadot/extension-dapp': - specifier: 0.58.1 - version: 0.58.1(@polkadot/api@15.3.1)(@polkadot/util-crypto@13.3.1(@polkadot/util@13.3.1))(@polkadot/util@13.3.1) '@polkadot/keyring': specifier: 13.3.1 version: 13.3.1(@polkadot/util-crypto@13.3.1(@polkadot/util@13.3.1))(@polkadot/util@13.3.1) @@ -89,6 +86,9 @@ importers: '@substrate/txwrapper-polkadot': specifier: 7.5.3 version: 7.5.3(@polkadot/util-crypto@13.3.1(@polkadot/util@13.3.1))(@polkadot/util@13.3.1) + '@talismn/connect-wallets': + specifier: 1.2.8 + version: 1.2.8(@polkadot/api@15.3.1)(@polkadot/extension-inject@0.58.1(@polkadot/api@15.3.1)(@polkadot/util@13.3.1)) '@walletconnect/core': specifier: 2.17.3 version: 2.17.3 @@ -1667,14 +1667,6 @@ packages: resolution: {integrity: sha512-RPJeAZLDEj9qY+vBL88gNrx5CSxzNw4Ns1v/GEcGIA8ZZ96TQTMTHFTs0jbS8o2oKGuiXlh/q2URviEGyRus8Q==} engines: {node: '>=18'} - '@polkadot/extension-dapp@0.58.1': - resolution: {integrity: sha512-fSRE6Ba6SoayrLMGvYUbRmN5PjOgiJHynjLizLo0DXzZ8wuFp9fGMnxxEX/s/L/hZIsn+QIvMrl9Wk4DbXx0sQ==} - engines: {node: '>=18'} - peerDependencies: - '@polkadot/api': '*' - '@polkadot/util': '*' - '@polkadot/util-crypto': '*' - '@polkadot/extension-inject@0.58.1': resolution: {integrity: sha512-Mz/qy5aHPvtQEEO44FIc36p+H18pBgyXSDAbPKzKKTurVQbD9cTpfhIALuZKptaGo7CpIxQf2jVhaZYgYAKxXw==} engines: {node: '>=18'} @@ -2930,6 +2922,12 @@ packages: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} + '@talismn/connect-wallets@1.2.8': + resolution: {integrity: sha512-/aniEZxOUNOaOEctHDUb/1jNFgKNsmeQ3L+pm4KvfYqb+C3HjZeBxykHEIc+5xmdR0GgCm30N8QzYWv6voM/lQ==} + peerDependencies: + '@polkadot/api': '>=9.3.3' + '@polkadot/extension-inject': '>=0.44.6' + '@tanstack/react-virtual@3.11.2': resolution: {integrity: sha512-OuFzMXPF4+xZgx8UzJha0AieuMihhhaWG0tCqpp6tDzlFwOmNBPYMuLOtMJ1Tr4pXLHmgjcWhG6RlknY2oNTdQ==} peerDependencies: @@ -10075,18 +10073,6 @@ snapshots: - supports-color - utf-8-validate - '@polkadot/extension-dapp@0.58.1(@polkadot/api@15.3.1)(@polkadot/util-crypto@13.3.1(@polkadot/util@13.3.1))(@polkadot/util@13.3.1)': - dependencies: - '@polkadot/api': 15.3.1 - '@polkadot/extension-inject': 0.58.1(@polkadot/api@15.3.1)(@polkadot/util@13.3.1) - '@polkadot/util': 13.3.1 - '@polkadot/util-crypto': 13.3.1(@polkadot/util@13.3.1) - tslib: 2.8.1 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - '@polkadot/extension-inject@0.58.1(@polkadot/api@15.3.1)(@polkadot/util@13.3.1)': dependencies: '@polkadot/api': 15.3.1 @@ -11584,6 +11570,11 @@ snapshots: dependencies: defer-to-connect: 2.0.1 + '@talismn/connect-wallets@1.2.8(@polkadot/api@15.3.1)(@polkadot/extension-inject@0.58.1(@polkadot/api@15.3.1)(@polkadot/util@13.3.1))': + dependencies: + '@polkadot/api': 15.3.1 + '@polkadot/extension-inject': 0.58.1(@polkadot/api@15.3.1)(@polkadot/util@13.3.1) + '@tanstack/react-virtual@3.11.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/virtual-core': 3.11.2 diff --git a/src/renderer/features/operations/OperationSign/model/polkadotExtensionSign.ts b/src/renderer/features/operations/OperationSign/model/polkadotExtensionSign.ts index 6101d5e118..403098c242 100644 --- a/src/renderer/features/operations/OperationSign/model/polkadotExtensionSign.ts +++ b/src/renderer/features/operations/OperationSign/model/polkadotExtensionSign.ts @@ -1,5 +1,5 @@ import { type ApiPromise } from '@polkadot/api'; -import { web3Enable, web3FromAddress } from '@polkadot/extension-dapp'; +import { getWalletBySource } from '@talismn/connect-wallets'; import { createEffect, createStore, sample } from 'effector'; import { createGate } from 'effector-react'; @@ -8,6 +8,7 @@ import { series } from '@/shared/effector'; import { assert, createTxMetadata, toAddress } from '@/shared/lib/utils'; import { networkModel } from '@/entities/network'; import { transactionService } from '@/entities/transaction'; +import { polkadotExtensionService } from '@/features/polkadot-extension-wallet'; import { type SigningPayload } from '../lib/types'; type Step = 'idle' | 'signing' | 'rejected' | 'failed' | 'success'; @@ -30,24 +31,29 @@ type SetupParams = { const signFx = createEffect(async ({ payload, apis }: SetupParams): Promise => { const api = apis[payload.transaction.chainId]; const account = payload.signatory || payload.account; + assert(api, `Api from chain ${payload.transaction.chainId} not found.`); assert(account, 'Signing account not found'); + if (!polkadotExtensionService.isPolkadotExtensionAccount(account)) throw new Error('Incorrect account for signing'); + const address = toAddress(account.accountId, { prefix: payload.chain.addressPrefix }); - const metadata = await createTxMetadata(address, api); + const wallet = getWalletBySource(account.extension); + assert(wallet, 'Wallet not found'); + + const metadata = await createTxMetadata(address, api); const txPayload = transactionService.createPayloadWithMetadata(payload.transaction, api, metadata); transactionService.logPayload([txPayload]); // Init connection - await web3Enable('Nova Spektr'); - // Fetching actual account injector - const injector = await web3FromAddress(address); + await wallet.enable('Nova Spektr'); // Method for signing - const signPayload = injector?.signer?.signPayload; + const signPayload = wallet?.signer?.signPayload; assert(signPayload, 'Signer not found'); + // @ts-expect-error No types for signPayload method const { signature } = await signPayload(txPayload.unsigned); return { @@ -61,7 +67,7 @@ const signAllFx = series(signFx); sample({ clock: flow.open, source: networkModel.$apis, - fn: (apis, { payloads }) => { + fn(apis, { payloads }) { return payloads.map((payload) => ({ payload, apis, diff --git a/src/renderer/features/polkadot-extension-wallet/components/PairingModal.tsx b/src/renderer/features/polkadot-extension-wallet/components/PairingModal.tsx index 9f1240886e..d30fb4085f 100644 --- a/src/renderer/features/polkadot-extension-wallet/components/PairingModal.tsx +++ b/src/renderer/features/polkadot-extension-wallet/components/PairingModal.tsx @@ -10,12 +10,15 @@ import { Box, Carousel, Field, Input, Modal, Select } from '@/shared/ui-kit'; import { accountsService } from '@/domains/network'; import { networkModel } from '@/entities/network'; import { pairingForm } from '../model/pairingForm'; +import { type ExtensionType } from '../types'; import { EmptyState } from './EmptyState'; -type Props = PropsWithChildren; +type Props = PropsWithChildren<{ + extension: ExtensionType; +}>; -export const PairingModal = ({ children }: Props) => { +export const PairingModal = ({ extension, children }: Props) => { const { t } = useI18n(); const open = useUnit(pairingForm.flow.status); @@ -46,11 +49,11 @@ export const PairingModal = ({ children }: Props) => { const toggleModal = (open: boolean) => { if (open) { - pairingForm.flow.open(); + pairingForm.flow.open({ extension }); } else { setName(''); setSelectedAccount(null); - pairingForm.flow.close(); + pairingForm.flow.close({ extension: null }); } }; @@ -66,7 +69,7 @@ export const PairingModal = ({ children }: Props) => { {t('onboarding.polkadotExtension.permissionStep')} - @@ -104,7 +107,7 @@ export const PairingModal = ({ children }: Props) => { {t('onboarding.polkadotExtension.requestRejected')} - diff --git a/src/renderer/features/polkadot-extension-wallet/components/WalletGroup.tsx b/src/renderer/features/polkadot-extension-wallet/components/WalletGroup.tsx index dfc407ec29..ec91abedfc 100644 --- a/src/renderer/features/polkadot-extension-wallet/components/WalletGroup.tsx +++ b/src/renderer/features/polkadot-extension-wallet/components/WalletGroup.tsx @@ -3,7 +3,7 @@ import { memo } from 'react'; import { type Wallet } from '@/shared/core'; import { Slot, createSlot } from '@/shared/di'; import { performSearch } from '@/shared/lib/utils'; -import { Icon } from '@/shared/ui'; +import { Icon, type IconNames } from '@/shared/ui'; import { Accordion, Box } from '@/shared/ui-kit'; import { WalletCardMd } from '@/entities/wallet'; import { walletsFiatBalanceFeature } from '@/features/wallet-fiat-balance'; @@ -17,12 +17,13 @@ export const walletActionsSlot = createSlot<{ wallet: Wallet }>(); type Props = { title: string; + icon: IconNames; wallets: Wallet[]; query: string; onSelect: (wallet: Wallet) => unknown; }; -export const WalletGroup = memo(({ wallets, query, title, onSelect }: Props) => { +export const WalletGroup = memo(({ wallets, icon, query, title, onSelect }: Props) => { const filteredWallets = performSearch({ query, records: wallets, @@ -37,7 +38,7 @@ export const WalletGroup = memo(({ wallets, query, title, onSelect }: Props) => - + {title} {wallets.length} diff --git a/src/renderer/features/polkadot-extension-wallet/constants.ts b/src/renderer/features/polkadot-extension-wallet/constants.ts new file mode 100644 index 0000000000..5f3cf21e4f --- /dev/null +++ b/src/renderer/features/polkadot-extension-wallet/constants.ts @@ -0,0 +1,10 @@ +import { type IconNames } from '@/shared/ui'; + +import { type ExtensionType } from './types'; + +export const walletIcon: Record = { + 'polkadot-js': { + icon: 'polkadotExtensionBackground', + onboarding: 'polkadotExtensionOnboarding', + }, +}; diff --git a/src/renderer/features/polkadot-extension-wallet/index.tsx b/src/renderer/features/polkadot-extension-wallet/index.tsx index c5e7678c8f..d5dcd12d02 100644 --- a/src/renderer/features/polkadot-extension-wallet/index.tsx +++ b/src/renderer/features/polkadot-extension-wallet/index.tsx @@ -12,6 +12,7 @@ import { onboardingActionsSlot } from '@/pages/Onboarding'; import { PairingModal } from './components/PairingModal'; import { WalletGroup, walletActionsSlot } from './components/WalletGroup'; +import { walletIcon } from './constants'; import { polkadotExtensionWalletFeature } from './model/feature'; import { wallets } from './model/wallets'; import { polkadotExtensionService } from './service'; @@ -31,16 +32,16 @@ polkadotExtensionWalletFeature.inject(accountsService.accountActionPermissionAny polkadotExtensionWalletFeature.inject(walletIconSlot, ({ wallet, size }) => { if (!polkadotExtensionService.isPolkadotExtensionWallet(wallet)) return null; - return ; + return ; }); polkadotExtensionWalletFeature.inject(walletPairingDropdownOptionsSlot, { order: 3, render({ t }) { return ( - + - + {t('wallets.addPolkadotExtension')} @@ -54,11 +55,11 @@ polkadotExtensionWalletFeature.inject(onboardingActionsSlot, { const { t } = useI18n(); return ( - + @@ -70,12 +71,13 @@ polkadotExtensionWalletFeature.inject(walletGroupSlot, { order: 0, render({ query, onSelect }) { const { t } = useI18n(); - const walletsList = useUnit(wallets.$list); + const polkadot = useUnit(wallets.$polkadot); return ( diff --git a/src/renderer/features/polkadot-extension-wallet/model/pairingForm.ts b/src/renderer/features/polkadot-extension-wallet/model/pairingForm.ts index 70971daa5a..899e7ffa62 100644 --- a/src/renderer/features/polkadot-extension-wallet/model/pairingForm.ts +++ b/src/renderer/features/polkadot-extension-wallet/model/pairingForm.ts @@ -1,67 +1,89 @@ -import { web3Accounts, web3Enable } from '@polkadot/extension-dapp'; -import { attach, createEffect, createEvent, createStore, sample } from 'effector'; +import { type Wallet as ConnectWallet, type WalletAccount } from '@talismn/connect-wallets'; +import { attach, combine, createEffect, createEvent, createStore, sample } from 'effector'; import { createGate } from 'effector-react'; import { CryptoType, SigningType, WalletType } from '@/shared/core'; -import { toAccountId, toShortAddress } from '@/shared/lib/utils'; +import { waitFor } from '@/shared/effector'; +import { nonNullable, nullable, toAccountId, toShortAddress } from '@/shared/lib/utils'; import { type AnyAccountDraft } from '@/domains/network'; import { walletModel } from '@/entities/wallet'; -import { type PolkadotExtensionAccount } from '../types'; +import { type ExtensionType, type PolkadotExtensionAccount } from '../types'; + +import { wallets } from './wallets'; type Step = 'idle' | 'pairing' | 'select' | 'rejected' | 'success'; -type InjectedExtension = Awaited>[number]; -type InjectedAccountWithMeta = Awaited>[number]; -type AccountDraft = AnyAccountDraft; +type ConnectedAccount = WalletAccount & { + type: 'sr25519' | 'ed25519' | 'ecdsa' | 'ethereum'; +}; -const flow = createGate(); +type AccountDraft = AnyAccountDraft; +const reconnect = createEvent(); const create = createEvent<{ name: string; account: AccountDraft }>(); +const flow = createGate<{ extension: ExtensionType | null }>({ defaultState: { extension: null } }); + +const $extensionType = flow.state.map(({ extension }) => extension); +const $wallet = combine( + $extensionType, + wallets.$connectedWallets, + (type, wallets) => wallets.find((w) => w.extensionName === type) ?? null, +); const $step = createStore('idle'); -const $extensions = createStore([]); -const $rawAccounts = createStore([]); +const $rawAccounts = createStore([]); -const cryptoTypeMap: Record['type'], CryptoType> = { +const cryptoTypeMap: Record = { ecdsa: CryptoType.ECDSA, ed25519: CryptoType.ED25519, ethereum: CryptoType.ETHEREUM, sr25519: CryptoType.SR25519, }; -const $accounts = $rawAccounts.map((accounts) => { - return accounts.map(({ address, type, meta }) => { +const $accounts = combine($rawAccounts, $extensionType, (accounts, extensionType) => { + if (nullable(extensionType)) return []; + + return accounts.map(({ address, type, name }) => { return { walletId: 0, - accountType: 'polkadot_extension', + accountType: 'extension', + extension: extensionType, accountId: toAccountId(address), - cryptoType: type ? cryptoTypeMap[type] : CryptoType.SR25519, - name: meta.name ?? toShortAddress(address), + cryptoType: type ? (cryptoTypeMap[type] ?? CryptoType.SR25519) : CryptoType.SR25519, + name: name ?? toShortAddress(address), type: 'universal', signingType: SigningType.POLKADOT_EXTENSION, }; }); }); -const requestInjectedExtensionsFx = createEffect(() => web3Enable('Nova Spektr')); -const requestAccessToAccountsFx = createEffect(() => web3Accounts()); +const requestAccessToAccountsFx = createEffect(async (wallet: ConnectWallet) => { + await wallet.enable('Nova Spektr'); + + return wallet.getAccounts() as Promise; +}); const createWalletFx = attach({ effect: walletModel.createWallet }); const receivedEmptyAccountList = requestAccessToAccountsFx.doneData.filter({ fn: (a) => a.length === 0 }); const receivedAccountList = requestAccessToAccountsFx.doneData.filter({ fn: (a) => a.length > 0 }); -sample({ - clock: flow.open, - target: requestInjectedExtensionsFx, +const readyToPair = waitFor({ + source: flow.open, + clock: $wallet, + filter: nonNullable, + reset: flow.close, }); -sample({ - clock: requestInjectedExtensionsFx.doneData, - target: $extensions, +const readyToReconnect = waitFor({ + source: reconnect, + clock: $wallet, + filter: nonNullable, + reset: flow.close, }); sample({ - clock: requestInjectedExtensionsFx.doneData, + clock: [readyToPair, readyToReconnect], + fn: ({ trigger: wallet }) => wallet, target: requestAccessToAccountsFx, }); @@ -77,6 +99,7 @@ sample({ external: false, wallet: { name: name.trim(), + extension: account.extension, type: WalletType.POLKADOT_EXTENSION, signingType: SigningType.POLKADOT_EXTENSION, }, @@ -88,6 +111,7 @@ sample({ sample({ clock: createWalletFx.done, + fn: () => ({ extension: null }), target: flow.close, }); @@ -100,13 +124,13 @@ sample({ }); sample({ - clock: requestInjectedExtensionsFx, + clock: requestAccessToAccountsFx, fn: () => 'pairing' as const, target: $step, }); sample({ - clock: [receivedEmptyAccountList, requestInjectedExtensionsFx.fail, requestAccessToAccountsFx.fail], + clock: [receivedEmptyAccountList, requestAccessToAccountsFx.fail], fn: () => 'rejected' as const, target: $step, }); @@ -122,9 +146,7 @@ export const pairingForm = { $step, $accounts, - $extensions, create, - requestPermission: requestInjectedExtensionsFx, - requestAccessToAccounts: requestAccessToAccountsFx, + reconnect, }; diff --git a/src/renderer/features/polkadot-extension-wallet/model/wallets.ts b/src/renderer/features/polkadot-extension-wallet/model/wallets.ts index b4241a9119..abe33cf975 100644 --- a/src/renderer/features/polkadot-extension-wallet/model/wallets.ts +++ b/src/renderer/features/polkadot-extension-wallet/model/wallets.ts @@ -1,8 +1,34 @@ +import { type Wallet as ConnectWallet, getWallets } from '@talismn/connect-wallets'; +import { createEffect, createStore, sample } from 'effector'; + import { walletModel } from '@/entities/wallet'; import { polkadotExtensionService } from '../service'; -const $list = walletModel.$wallets.map((wallets) => wallets.filter(polkadotExtensionService.isPolkadotExtensionWallet)); +import { polkadotExtensionWalletFeature } from './feature'; + +const $connectedWallets = createStore([]); + +const $all = walletModel.$wallets.map((wallets) => wallets.filter(polkadotExtensionService.isPolkadotExtensionWallet)); +const $polkadot = $all.map((wallets) => wallets.filter((w) => w.extension === 'polkadot-js')); + +const requestWalletsFx = createEffect(() => + getWallets() + .filter((e) => e.installed) + .filter((e) => e.title !== 'Nova Wallet'), +); + +sample({ + clock: polkadotExtensionWalletFeature.running, + target: requestWalletsFx, +}); + +sample({ + clock: requestWalletsFx.doneData, + target: $connectedWallets, +}); export const wallets = { - $list, + $connectedWallets, + $all, + $polkadot, }; diff --git a/src/renderer/features/polkadot-extension-wallet/service.ts b/src/renderer/features/polkadot-extension-wallet/service.ts index 0593011d08..cd34bdc322 100644 --- a/src/renderer/features/polkadot-extension-wallet/service.ts +++ b/src/renderer/features/polkadot-extension-wallet/service.ts @@ -9,9 +9,7 @@ function isPolkadotExtensionWallet(wallet: Wallet): wallet is PolkadotExtensionW function isPolkadotExtensionAccount(account: AnyAccount): account is PolkadotExtensionAccount { return ( - accountsService.isUniversalAccount(account) && - 'accountType' in account && - account['accountType'] === 'polkadot_extension' + accountsService.isUniversalAccount(account) && 'accountType' in account && account['accountType'] === 'extension' ); } diff --git a/src/renderer/features/polkadot-extension-wallet/types.ts b/src/renderer/features/polkadot-extension-wallet/types.ts index 9024b2a210..cf20be2664 100644 --- a/src/renderer/features/polkadot-extension-wallet/types.ts +++ b/src/renderer/features/polkadot-extension-wallet/types.ts @@ -1,10 +1,15 @@ import { type Wallet, type WalletType } from '@/shared/core'; import { type UniversalAccount } from '@/domains/network'; +// TODO add more extensions +export type ExtensionType = 'polkadot-js'; + export type PolkadotExtensionWallet = Wallet & { type: WalletType.POLKADOT_EXTENSION; + extension: ExtensionType; }; export interface PolkadotExtensionAccount extends UniversalAccount { - accountType: 'polkadot_extension'; + accountType: 'extension'; + extension: ExtensionType; } diff --git a/src/renderer/features/wallet-polkadot-vault/index.tsx b/src/renderer/features/wallet-polkadot-vault/index.tsx index 4e58272105..3a0dfbf190 100644 --- a/src/renderer/features/wallet-polkadot-vault/index.tsx +++ b/src/renderer/features/wallet-polkadot-vault/index.tsx @@ -1,4 +1,3 @@ -import { isWeb3Injected } from '@polkadot/extension-dapp'; import { useUnit } from 'effector-react'; import { $features } from '@/shared/config/features'; @@ -16,7 +15,7 @@ export { walletActionsSlot }; export const walletPolkadotVaultFeature = createFeature({ name: 'wallet/polkadot vault', - enable: $features.map(f => f.polkadotVault && isWeb3Injected), + enable: $features.map(f => f.polkadotVault), }); walletPolkadotVaultFeature.inject(accountsService.accountActionPermissionAnyOf, ({ account }) => { diff --git a/src/renderer/shared/config/features/index.ts b/src/renderer/shared/config/features/index.ts index 36251fb0ae..80d27efec9 100644 --- a/src/renderer/shared/config/features/index.ts +++ b/src/renderer/shared/config/features/index.ts @@ -2,7 +2,7 @@ import { type UnitValue, combine, createEvent, createStore, sample } from 'effec import { persist } from 'effector-storage/local'; import { produce } from 'immer'; -import { isDev, isWeb } from '@/shared/lib/utils'; +import { isDev } from '@/shared/lib/utils'; type Features = UnitValue; @@ -29,7 +29,7 @@ export const $defaultFeatures = createStore({ walletConnect: true, watchOnly: true, ledger: true, - polkadotExtension: isDev() && isWeb(), + polkadotExtension: isDev(), }); export const $features = combine($defaultFeatures, $mutatedFeatures, (base, extend) => ({ ...base, ...extend })); diff --git a/src/renderer/shared/constants/testIds.ts b/src/renderer/shared/constants/testIds.ts index 49c0764c5d..318ba22fb3 100644 --- a/src/renderer/shared/constants/testIds.ts +++ b/src/renderer/shared/constants/testIds.ts @@ -6,6 +6,7 @@ export const TEST_IDS = { WALLET_CONNECT_BUTTON: 'onboarding-wallet-connect-button', LEDGER_BUTTON: 'onboarding-ledger-button', POLKADOT_EXTENSION_BUTTON: 'onboarding-polkadot-extension-button', + TALISMAN_BUTTON: 'onboarding-talisman-extension-button', WALLET_NAME_INPUT: 'onboarding-wallet-name-input', WALLET_ADDRESS_INPUT: 'onboarding-wallet-address-input', },